Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[R] Added ApiClient and fixed other issues #6571

Merged
merged 10 commits into from
Oct 4, 2017
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)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@brnleehng thanks for the PR. Does it mean developers (users of the SDK) can no longer use a different base path during runtime when constructing the class?

Copy link
Contributor

@wing328 wing328 Sep 29, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah please ignore my question. You've moved "basePath" to apiClient.

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