Skip to content

Commit

Permalink
[R] Added ApiClient and fixed other issues (#6571)
Browse files Browse the repository at this point in the history
* Added namespace mustache to be generated

* Fixed syntax issues with package generation

* Added Response and Element mustache templates

* Added ApiClient

* Fix: Only required parameters needed for api operations

* Added documentation generated code

* Regenerated petstore samples

* Fixed url paths for operations

* Fixed based on comments in issues #6520

* Regenerated petstore samples
  • Loading branch information
brnleehng authored and wing328 committed Oct 4, 2017
1 parent e49e7a0 commit 61b910f
Show file tree
Hide file tree
Showing 19 changed files with 1,207 additions and 551 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ public void processOpts() {
supportingFiles.add(new SupportingFile("description.mustache", "", "DESCRIPTION"));
supportingFiles.add(new SupportingFile("Rbuildignore.mustache", "", ".Rbuildignore"));
supportingFiles.add(new SupportingFile(".travis.yml", "", ".travis.yml"));
supportingFiles.add(new SupportingFile("response.mustache", "/R", "Response.r"));
supportingFiles.add(new SupportingFile("element.mustache", "/R", "Element.r"));
supportingFiles.add(new SupportingFile("api_client.mustache", "/R", "ApiClient.r"));
}

@Override
Expand Down
121 changes: 85 additions & 36 deletions modules/swagger-codegen/src/main/resources/r/api.mustache
Original file line number Diff line number Diff line change
@@ -1,56 +1,105 @@
{{>partial_header}}
{{#operations}}
#' @title {{baseName}} operations
#' @description {{importPath}}
#'
#' @field path Stores url path of the request.
#' @field apiClient Handles the client-server communication.
#' @field userAgent Set the user agent of the request.
#'
#' @importFrom R6 R6Class
#'
#' @section Methods:
#' \describe{
{{#operation}}
#'
#' {{operationId}} {{summary}}
#'
{{/operation}}
#' }
#'
#' @export
{{classname}} <- R6::R6Class(
'{{classname}}',
public = list(
userAgent = "{{#httpUserAgent}}{{{.}}}{{/httpUserAgent}}{{^httpUserAgent}}Swagger-Codegen/{{{packageVersion}}}/r{{/httpUserAgent}}",
basePath = "{{{basePath}}}",
initialize = function(basePath){
if (!missing(basePath)) {
stopifnot(is.character(basePath), length(basePath) == 1)
self$basePath <- basePath
apiClient = NULL,
initialize = function(apiClient){
if (!missing(apiClient)) {
self$apiClient <- apiClient
}
else {
self$apiClient <- ApiClient$new()
}
},

{{#operation}}
{{operationId}} = function({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}){
resp <- httr::{{httpMethod}}(paste0(self$basePath{{#pathParams}}, {{paramName}}{{/pathParams}}),
httr::add_headers("User-Agent" = self$userAgent{{#hasConsumes}}, "accept" = "{{#consumes}}{{#-first}}{{{mediaType}}}{{/-first}}{{/consumes}}"{{/hasConsumes}}{{#hasProduces}}, "content-type" = "{{#produces}}{{#-first}}{{{mediaType}}}{{/-first}}{{/produces}}"{{/hasProduces}}{{#headerParams}}, "{{baseName}}" = {{paramName}}{{/headerParams}})
{{#hasFormParams}}
,body = list(
{{#formParams}}
{{^isFile}}
"{{baseName}}" = {{paramName}}{{#hasMore}},{{/hasMore}}
{{/isFile}}
{{#isFile}}
"{{baseName}}" = httr::upload_file({{paramName}}){{#hasMore}},{{/hasMore}}
{{/isFile}}
{{/formParams}}
)
{{/hasFormParams}}
{{#bodyParams}}
,body = {{paramName}}$toJSON()
{{/bodyParams}}
{{#hasQueryParams}}
,query = list(
{{#queryParams}}
"{{baseName}}" = {{paramName}}{{#hasMore}},{{/hasMore}}
{{/queryParams}}
)
{{/hasQueryParams}}
)
{{operationId}} = function({{#allParams}}{{paramName}}, {{/allParams}}...){
args <- list(...)
body <- NULL
queryParams <- list()
headerParams <- character()
{{#hasHeaderParams}}
{{#headerParams}}
if (!missing(`{{paramName}}`)) {
headerParams['{{baseName}}'] <- `{{paramName}}`
}
{{/headerParams}}
{{/hasHeaderParams}}
{{#hasQueryParams}}
{{#queryParams}}
if (!missing(`{{paramName}}`)) {
queryParams['{{baseName}}'] <- {{paramName}}
}
{{/queryParams}}
{{/hasQueryParams}}
{{#hasFormParams}}
body <- list(
{{#formParams}}
{{^isFile}}
"{{baseName}}" = {{paramName}}{{#hasMore}},{{/hasMore}}
{{/isFile}}
{{#isFile}}
"{{baseName}}" = httr::upload_file({{paramName}}){{#hasMore}},{{/hasMore}}
{{/isFile}}
{{/formParams}}
)
{{/hasFormParams}}
{{#hasBodyParam}}
{{#bodyParams}}
if (!missing(`{{paramName}}`)) {
body <- `{{paramName}}`$toJSON()
}
{{/bodyParams}}
{{/hasBodyParam}}

urlPath <- "{{path}}"
{{#hasPathParams}}
{{#pathParams}}
if (!missing(`{{paramName}}`)) {
urlPath <- gsub(paste0("\\{", "{{baseName}}", "\\}"), `{{paramName}}`, urlPath)
}
{{/pathParams}}
{{/hasPathParams}}

resp <- self$apiClient$callApi(url = paste0(self$apiClient$basePath, urlPath),
method = "{{httpMethod}}",
queryParams = queryParams,
headerParams = headerParams,
body = body,
...)

if (httr::status_code(resp) >= 200 && httr::status_code(resp) <= 299) {
{{#returnType}}
result <- {{returnType}}$new()$fromJSON(httr::content(resp, "text", encoding = "UTF-8"), simplifyVector = FALSE)
Response$new(result, resp)
returnObject <- {{returnType}}$new()
result <- returnObject$fromJSON(httr::content(resp, "text", encoding = "UTF-8"))
Response$new(returnObject, resp)
{{/returnType}}
{{^returnType}}
# void response, no need to return anything
{{/returnType}}
} else if (httr::status_code(resp) >= 400 && httr::status_code(resp) <= 499){
} else if (httr::status_code(resp) >= 400 && httr::status_code(resp) <= 499) {
Response$new("API client error", resp)
} else if (httr::status_code(resp) >= 500 && httr::status_code(resp) <= 599){
} else if (httr::status_code(resp) >= 500 && httr::status_code(resp) <= 599) {
Response$new("API server error", resp)
}

Expand Down
64 changes: 64 additions & 0 deletions modules/swagger-codegen/src/main/resources/r/api_client.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{{>partial_header}}

#' ApiClient Class
#'
#' Generic API client for Swagger client library builds.
#' Swagger generic API client. This client handles the client-
#' server communication, and is invariant across implementations. Specifics of
#' the methods and models for each application are generated from the Swagger
#' templates.
#'
#' NOTE: This class is auto generated by the swagger code generator program.
#' Ref: https://github.com/swagger-api/swagger-codegen
#' Do not edit the class manually.
#'
#' @export
ApiClient <- R6::R6Class(
'ApiClient',
public = list(
basePath = "{{{basePath}}}",
configuration = NULL,
userAgent = NULL,
defaultHeaders = NULL,
initialize = function(basePath, configuration, defaultHeaders){
if (!missing(basePath)) {
self$basePath <- basePath
}

if (!missing(configuration)) {
self$configuration <- configuration
}

if (!missing(defaultHeaders)) {
self$defaultHeaders <- defaultHeaders
}

self$`userAgent` <- '{{#httpUserAgent}}{{{.}}}{{/httpUserAgent}}{{^httpUserAgent}}Swagger-Codegen/{{{packageVersion}}}/r{{/httpUserAgent}}'
},
callApi = function(url, method, queryParams, headerParams, body, ...){
headers <- httr::add_headers(headerParams)

if (method == "GET") {
httr::GET(url, queryParams, headers, ...)
}
else if (method == "POST") {
httr::POST(url, queryParams, headers, body = body, ...)
}
else if (method == "PUT") {
httr::PUT(url, queryParams, headers, body = body, ...)
}
else if (method == "PATCH") {
httr::PATCH(url, queryParams, headers, body = body, ...)
}
else if (method == "HEAD") {
httr::HEAD(url, queryParams, headers, ...)
}
else if (method == "DELETE") {
httr::DELETE(url, queryParams, headers, ...)
}
else {
stop("http method must be `GET`, `HEAD`, `OPTIONS`, `POST`, `PATCH`, `PUT` or `DELETE`.")
}
}
)
)
24 changes: 24 additions & 0 deletions modules/swagger-codegen/src/main/resources/r/element.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#' Element Class
#'
#' Element Class
#' @export
Element <- R6::R6Class(
'Element',
public = list(
id = NULL,
name = NULL,
initialize = function(id,name){
if (!missing(id)) {
stopifnot(is.numeric(id), length(id) == 1)
self$id <- id
}
if (!missing(name)) {
stopifnot(is.character(name), length(name) == 1)
self$name <- name
}
},
toJSON = function() {
sprintf('{"id":%d,"name":"%s"}', self$id, self$name)
}
)
)
97 changes: 48 additions & 49 deletions modules/swagger-codegen/src/main/resources/r/model.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@
{{#model}}
{{>partial_header}}


#' {{classname}} Class
#'
{{#vars}}
#' @field {{baseName}} {{title}}
{{/vars}}
#'
#' @importFrom R6 R6Class
#' @importFrom jsonlite fromJSON toJSON
#' @export
{{classname}} <- R6::R6Class(
'{{classname}}',
Expand Down Expand Up @@ -37,8 +43,7 @@
stopifnot(is.character(`{{baseName}}`), length(`{{baseName}}`) == 1)
{{/isDateTime}}
{{^isPrimitiveType}}
stopifnot(is.list(tags), length(tags) != 0)
lapply(`{{baseName}}`, function(x) stopifnot("Element" %in% class(x), !is.list(x)))
stopifnot(R6::is.R6(`{{baseName}}`))
{{/isPrimitiveType}}
{{/isListContainer}}
{{#isListContainer}}
Expand All @@ -47,15 +52,49 @@
lapply(`{{baseName}}`, function(x) stopifnot(is.character(x)))
{{/isPrimitiveType}}
{{^isPrimitiveType}}
stopifnot(is.list(tags), length(tags) != 0)
lapply(`{{baseName}}`, function(x) stopifnot("Element" %in% class(x), !is.list(x)))
stopifnot(is.list(`{{baseName}}`), length(`{{baseName}}`) != 0)
lapply(`{{baseName}}`, function(x) stopifnot(R6::is.R6(x)))
{{/isPrimitiveType}}
{{/isListContainer}}
self$`{{baseName}}` <- `{{baseName}}`
}
{{/vars}}
},
toJSON = function() {
{{classname}}Object <- list()
{{#vars}}
if (!is.null(self$`{{baseName}}`)) {
{{classname}}Object[['{{baseName}}']] <- {{#isListContainer}}{{#isPrimitiveType}}self$`{{baseName}}`{{/isPrimitiveType}}{{^isPrimitiveType}}lapply(self$`{{baseName}}`, function(x) x$toJSON()){{/isPrimitiveType}}{{/isListContainer}}{{^isListContainer}}self$`{{baseName}}`{{^isPrimitiveType}}$toJSON(){{/isPrimitiveType}}{{/isListContainer}}
}
{{/vars}}
{{classname}}Object
},
fromJSON = function({{classname}}Json) {
{{classname}}Object <- jsonlite::fromJSON({{classname}}Json)
{{#vars}}
if (!is.null({{classname}}Object$`{{baseName}}`)) {
{{#isPrimitiveType}}
self$`{{baseName}}` <- {{classname}}Object$`{{baseName}}`
{{/isPrimitiveType}}
{{^isPrimitiveType}}
{{#isListContainer}}
self$`{{baseName}}` <- lapply({{classname}}Object$`{{baseName}}`, function(x) {
{{baseName}}Object <- {{datatype}}$new()
{{baseName}}Object$fromJSON(jsonlite::toJSON(x, auto_unbox = TRUE))
{{baseName}}Object
})
{{/isListContainer}}
{{^isListContainer}}
{{baseName}}Object <- {{datatype}}$new()
{{baseName}}Object$fromJSON(jsonlite::toJSON({{classname}}Object${{baseName}}, auto_unbox = TRUE))
self$`{{baseName}}` <- {{baseName}}Object
{{/isListContainer}}
{{/isPrimitiveType}}
}
{{/vars}}
},
toJSONString = function() {
sprintf(
'{
{{#vars}}
Expand All @@ -77,64 +116,24 @@
{{/vars}}
)
},
fromJSON = function({{classname}}Json) {
fromJSONString = function({{classname}}Json) {
{{classname}}Object <- jsonlite::fromJSON({{classname}}Json)
{{#vars}}
{{#isPrimitiveType}}
self$`{{baseName}}` <- {{classname}}Object$`{{baseName}}`
{{/isPrimitiveType}}
{{^isPrimitiveType}}
{{#isListContainer}}
self$`{{baseName}}` <- lapply({{classname}}Object$`{{baseName}}`, function(x) {{datatype}}$new()$fromJSON(jsonlite::toJSON(x)))
self$`{{baseName}}` <- lapply({{classname}}Object$`{{baseName}}`, function(x) {{datatype}}$new()$fromJSON(jsonlite::toJSON(x, auto_unbox = TRUE)))
{{/isListContainer}}
{{^isListContainer}}
self$`{{baseName}}` <- {{datatype}}$new()$fromJSON(jsonlite::toJSON({{classname}}Object${{baseName}}))
{{datatype}}Object -> {{datatype}}$new()
self$`{{baseName}}` <- {{datatype}}Object$fromJSON(jsonlite::toJSON({{classname}}Object${{baseName}}, auto_unbox = TRUE))
{{/isListContainer}}
{{/isPrimitiveType}}
{{/vars}}
}
)
)

#' Element Class
#'
#' Element Class
#' @export
Element <- R6::R6Class(
'Element',
public = list(
id = NULL,
name = NULL,
initialize = function(id,name){
if (!missing(id)) {
stopifnot(is.numeric(id), length(id) == 1)
self$id <- id
}
if (!missing(name)) {
stopifnot(is.character(name), length(name) == 1)
self$name <- name
}
},
toJSON = function() {
sprintf('{"id":%d,"name":"%s"}', self$id, self$name)
}
)
)

#' Response Class
#'
#' Response Class
#' @export
Response <- R6::R6Class(
'Response',
public = list(
content = NULL,
response = NULL,
initialize = function(content, response){
self$content <- content
self$response <- response
}
)
)
{{/model}}
{{/models}}
Loading

0 comments on commit 61b910f

Please sign in to comment.