From f98753aa8bf9870c5d2e5a2b9c23cb0484ac607e Mon Sep 17 00:00:00 2001 From: William Cheng Date: Wed, 7 Sep 2022 12:21:13 +0800 Subject: [PATCH] [R] support explode (true/false) in query array parameters (#13364) * fix query parameters (explode or not) in r client * add tests --- .../src/main/resources/r/api.mustache | 9 +++++- .../r/libraries/httr2/api_client.mustache | 11 +++++-- .../src/test/resources/3_0/r/petstore.yaml | 9 +++--- .../petstore/R-httr2-wrapper/R/api_client.R | 11 +++++-- .../petstore/R-httr2-wrapper/R/pet_api.R | 12 ++------ .../petstore/R-httr2-wrapper/R/user_api.R | 4 +-- .../petstore/R-httr2-wrapper/docs/PetApi.md | 4 +-- .../petstore/R-httr2-wrapper/test_petstore.R | 28 +++++++++++++++++- .../tests/testthat/test_petstore.R | 29 +++++++++++++++++++ .../client/petstore/R-httr2/R/api_client.R | 11 +++++-- samples/client/petstore/R-httr2/R/pet_api.R | 12 ++------ samples/client/petstore/R-httr2/R/user_api.R | 4 +-- .../client/petstore/R-httr2/docs/PetApi.md | 4 +-- samples/client/petstore/R/R/pet_api.R | 12 ++------ samples/client/petstore/R/R/user_api.R | 4 +-- samples/client/petstore/R/docs/PetApi.md | 4 +-- 16 files changed, 114 insertions(+), 54 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/r/api.mustache b/modules/openapi-generator/src/main/resources/r/api.mustache index 8248d9db4f1..460a92365a0 100644 --- a/modules/openapi-generator/src/main/resources/r/api.mustache +++ b/modules/openapi-generator/src/main/resources/r/api.mustache @@ -382,12 +382,19 @@ {{/headerParams}} {{#queryParams}} {{#isArray}} + {{#isExplode}} + # explore for (query_item in `{{{paramName}}}`) { query_params[["{{{baseName}}}"]] <- c(query_params[["{{{baseName}}}"]], list(`{{{baseName}}}` = query_item)) } + {{/isExplode}} + {{^isExplode}} + # no explore + query_params[["{{{baseName}}}"]] <- I(paste(lapply(`{{{paramName}}}`, URLencode, reserved = TRUE), collapse = ",")) + {{/isExplode}} {{/isArray}} {{^isArray}} - query_params["{{baseName}}"] <- `{{paramName}}` + query_params[["{{baseName}}"]] <- `{{paramName}}` {{/isArray}} {{/queryParams}} diff --git a/modules/openapi-generator/src/main/resources/r/libraries/httr2/api_client.mustache b/modules/openapi-generator/src/main/resources/r/libraries/httr2/api_client.mustache index 5c151092160..4e664cf8e15 100644 --- a/modules/openapi-generator/src/main/resources/r/libraries/httr2/api_client.mustache +++ b/modules/openapi-generator/src/main/resources/r/libraries/httr2/api_client.mustache @@ -234,8 +234,15 @@ ApiClient <- R6::R6Class( } ## add query parameters - for (query_param in query_params) { - req <- req %>% req_url_query(!!!query_param) + for (query_param in names(query_params)) { + if (typeof(query_params[[query_param]]) == "list") { + # for explode, e.g. a=1,a=2,a=3 + req <- req %>% req_url_query(!!!query_params[[query_param]]) + } else { # for non-explode, e.g. a=1,2,3 + tmp <- list() + tmp[[query_param]] <- query_params[[query_param]] + req <- req %>% req_url_query(!!!tmp) + } } # has file upload? diff --git a/modules/openapi-generator/src/test/resources/3_0/r/petstore.yaml b/modules/openapi-generator/src/test/resources/3_0/r/petstore.yaml index 44dae3d03bc..76ff4f5a788 100644 --- a/modules/openapi-generator/src/test/resources/3_0/r/petstore.yaml +++ b/modules/openapi-generator/src/test/resources/3_0/r/petstore.yaml @@ -82,7 +82,7 @@ paths: description: Status values that need to be considered for filter required: true style: form - explode: false + explode: true # change to true for testing purpose deprecated: true schema: type: array @@ -148,9 +148,10 @@ paths: $ref: '#/components/schemas/Pet' '400': description: Invalid tag value - security: - - petstore_auth: - - 'read:pets' + # comment out for testing purpose + #security: + # - petstore_auth: + # - 'read:pets' deprecated: true '/pet/{petId}': get: diff --git a/samples/client/petstore/R-httr2-wrapper/R/api_client.R b/samples/client/petstore/R-httr2-wrapper/R/api_client.R index b730927db87..8e732ef66d3 100644 --- a/samples/client/petstore/R-httr2-wrapper/R/api_client.R +++ b/samples/client/petstore/R-httr2-wrapper/R/api_client.R @@ -226,8 +226,15 @@ ApiClient <- R6::R6Class( } ## add query parameters - for (query_param in query_params) { - req <- req %>% req_url_query(!!!query_param) + for (query_param in names(query_params)) { + if (typeof(query_params[[query_param]]) == "list") { + # for explode, e.g. a=1,a=2,a=3 + req <- req %>% req_url_query(!!!query_params[[query_param]]) + } else { # for non-explode, e.g. a=1,2,3 + tmp <- list() + tmp[[query_param]] <- query_params[[query_param]] + req <- req %>% req_url_query(!!!tmp) + } } # has file upload? diff --git a/samples/client/petstore/R-httr2-wrapper/R/pet_api.R b/samples/client/petstore/R-httr2-wrapper/R/pet_api.R index 2ad06857c35..ef23b725e3d 100644 --- a/samples/client/petstore/R-httr2-wrapper/R/pet_api.R +++ b/samples/client/petstore/R-httr2-wrapper/R/pet_api.R @@ -395,9 +395,6 @@ #' #Finds Pets by tags #' api_instance <- petstore_api$new() #' -#' # Configure OAuth2 access token for authorization: petstore_auth -#' api_instance$api_client$access_token <- Sys.getenv("ACCESS_TOKEN") -#' #' result <- tryCatch( #' #' # to save the result into a file, simply add the optional `data_file` parameter, e.g. @@ -944,6 +941,7 @@ PetApi <- R6::R6Class( } + # explore for (query_item in `status`) { query_params[["status"]] <- c(query_params[["status"]], list(`status` = query_item)) } @@ -1064,14 +1062,10 @@ PetApi <- R6::R6Class( } - for (query_item in `tags`) { - query_params[["tags"]] <- c(query_params[["tags"]], list(`tags` = query_item)) - } + # no explore + query_params[["tags"]] <- I(paste(lapply(`tags`, URLencode, reserved = TRUE), collapse = ",")) local_var_url_path <- "/pet/findByTags" - # OAuth-related settings - is_oauth <- TRUE - oauth_scopes <- "read:pets" # The Accept request HTTP header local_var_accepts <- list("application/xml", "application/json") diff --git a/samples/client/petstore/R-httr2-wrapper/R/user_api.R b/samples/client/petstore/R-httr2-wrapper/R/user_api.R index ef306b8fd22..55083d2ab24 100644 --- a/samples/client/petstore/R-httr2-wrapper/R/user_api.R +++ b/samples/client/petstore/R-httr2-wrapper/R/user_api.R @@ -1071,9 +1071,9 @@ UserApi <- R6::R6Class( } - query_params["username"] <- `username` + query_params[["username"]] <- `username` - query_params["password"] <- `password` + query_params[["password"]] <- `password` local_var_url_path <- "/user/login" diff --git a/samples/client/petstore/R-httr2-wrapper/docs/PetApi.md b/samples/client/petstore/R-httr2-wrapper/docs/PetApi.md index dd29240b90e..db8aa8d7a6a 100644 --- a/samples/client/petstore/R-httr2-wrapper/docs/PetApi.md +++ b/samples/client/petstore/R-httr2-wrapper/docs/PetApi.md @@ -213,8 +213,6 @@ var_tags <- list("inner_example") # array[character] | Tags to filter by # Finds Pets by tags api_instance <- petstore_api$new() -# Configure OAuth2 access token for authorization: petstore_auth -api_instance$api_client$access_token <- Sys.getenv("ACCESS_TOKEN") result <- tryCatch( # to save the result into a file, simply add the optional `data_file` parameter, e.g. # api_instance$pet_api$find_pets_by_tags(var_tags, data_file = "result.txt"), @@ -247,7 +245,7 @@ Name | Type | Description | Notes ### Authorization -[petstore_auth](../README.md#petstore_auth) +No authorization required ### HTTP request headers diff --git a/samples/client/petstore/R-httr2-wrapper/test_petstore.R b/samples/client/petstore/R-httr2-wrapper/test_petstore.R index f8c7c3b3c23..b34d197e003 100644 --- a/samples/client/petstore/R-httr2-wrapper/test_petstore.R +++ b/samples/client/petstore/R-httr2-wrapper/test_petstore.R @@ -3,7 +3,33 @@ install.packages("petstore_1.0.0.tar.gz",repos=NULL, type="source") library(petstore) library(jsonlite) -var_tags <- list("innerzzzzzzz", "second_example", "345") # array[character] | Tags to filter by +var_status <- list("something inside", "explode please", "123") # array[character] | Status values that need to be considered for filter + +# Finds Pets by status +api_instance <- petstore_api$new() +# Configure OAuth2 access token for authorization: petstore_auth +#api_instance$api_client$access_token <- Sys.getenv("ACCESS_TOKEN") +result <- tryCatch( + # to save the result into a file, simply add the optional `data_file` parameter, e.g. + # api_instance$pet_api$find_pets_by_status(var_status, data_file = "result.txt"), + api_instance$pet_api$find_pets_by_status(var_status), + ApiException = function(ex) ex + ) +# In case of error, print the error object +if (!is.null(result$ApiException)) { + print("Exception occurs when calling `find_pets_by_status`:") + dput(result$ApiException$toString()) + # error object + dput(result$ApiException$error_object$toJSONString()) +} else { + # deserialized response object + print("The response is ...") + dput(result) +} + + + +var_tags <- c("innerzzzzzzz", "second,example", "345") # array[character] | Tags to filter by # Finds Pets by tags api_instance <- petstore_api$new() diff --git a/samples/client/petstore/R-httr2-wrapper/tests/testthat/test_petstore.R b/samples/client/petstore/R-httr2-wrapper/tests/testthat/test_petstore.R index 6c052310d63..2fe987360bc 100644 --- a/samples/client/petstore/R-httr2-wrapper/tests/testthat/test_petstore.R +++ b/samples/client/petstore/R-httr2-wrapper/tests/testthat/test_petstore.R @@ -234,6 +234,35 @@ test_that("GetPetById with data_file", { expect_equal(response$name, "name_test") }) +test_that("find_pets_by_status", { + pet_tag_test <- Pet$new("name_test", + photoUrls = list("photo_test", "second test"), + category = Category$new(id = 4455, name = "test_cat"), + id = 4455, + tags = list( + Tag$new(id = 4455, name = "tag_test"), Tag$new(id = 488, name = "unknown 2") + ), + status = "available" + ) + result <- pet_api$add_pet(pet_tag_test) + + # vector as input + var_tags <- c("unknown", "unknown 2") # array[character] | Tags to filter by + result <- pet_api$find_pets_by_tags(var_tags) + expect_true(!is.null(result)) + expect_equal(result[[1]]$id, 123321) + expect_equal(result[[2]]$id, 123999) + expect_equal(result[[3]]$id, 4455) + + # list as input + var_tags <- list("unknown", "unknown 2") # array[character] | Tags to filter by + result <- pet_api$find_pets_by_tags(var_tags) + expect_true(!is.null(result)) + expect_equal(result[[1]]$id, 123321) + expect_equal(result[[2]]$id, 123999) + expect_equal(result[[3]]$id, 4455) +}) + test_that("Tests allOf", { # test allOf without discriminator a1 <- AllofTagApiResponse$new(id = 450, name = "test_cat", code = 200, type = "test_type", message = "test_message") diff --git a/samples/client/petstore/R-httr2/R/api_client.R b/samples/client/petstore/R-httr2/R/api_client.R index b730927db87..8e732ef66d3 100644 --- a/samples/client/petstore/R-httr2/R/api_client.R +++ b/samples/client/petstore/R-httr2/R/api_client.R @@ -226,8 +226,15 @@ ApiClient <- R6::R6Class( } ## add query parameters - for (query_param in query_params) { - req <- req %>% req_url_query(!!!query_param) + for (query_param in names(query_params)) { + if (typeof(query_params[[query_param]]) == "list") { + # for explode, e.g. a=1,a=2,a=3 + req <- req %>% req_url_query(!!!query_params[[query_param]]) + } else { # for non-explode, e.g. a=1,2,3 + tmp <- list() + tmp[[query_param]] <- query_params[[query_param]] + req <- req %>% req_url_query(!!!tmp) + } } # has file upload? diff --git a/samples/client/petstore/R-httr2/R/pet_api.R b/samples/client/petstore/R-httr2/R/pet_api.R index ad63cbf6087..891f456f355 100644 --- a/samples/client/petstore/R-httr2/R/pet_api.R +++ b/samples/client/petstore/R-httr2/R/pet_api.R @@ -395,9 +395,6 @@ #' #Finds Pets by tags #' api_instance <- PetApi$new() #' -#' # Configure OAuth2 access token for authorization: petstore_auth -#' api_instance$api_client$access_token <- Sys.getenv("ACCESS_TOKEN") -#' #' result <- tryCatch( #' #' # to save the result into a file, simply add the optional `data_file` parameter, e.g. @@ -944,6 +941,7 @@ PetApi <- R6::R6Class( } + # explore for (query_item in `status`) { query_params[["status"]] <- c(query_params[["status"]], list(`status` = query_item)) } @@ -1064,14 +1062,10 @@ PetApi <- R6::R6Class( } - for (query_item in `tags`) { - query_params[["tags"]] <- c(query_params[["tags"]], list(`tags` = query_item)) - } + # no explore + query_params[["tags"]] <- I(paste(lapply(`tags`, URLencode, reserved = TRUE), collapse = ",")) local_var_url_path <- "/pet/findByTags" - # OAuth-related settings - is_oauth <- TRUE - oauth_scopes <- "read:pets" # The Accept request HTTP header local_var_accepts <- list("application/xml", "application/json") diff --git a/samples/client/petstore/R-httr2/R/user_api.R b/samples/client/petstore/R-httr2/R/user_api.R index 9abfc3847bd..0d16d8ea51b 100644 --- a/samples/client/petstore/R-httr2/R/user_api.R +++ b/samples/client/petstore/R-httr2/R/user_api.R @@ -1071,9 +1071,9 @@ UserApi <- R6::R6Class( } - query_params["username"] <- `username` + query_params[["username"]] <- `username` - query_params["password"] <- `password` + query_params[["password"]] <- `password` local_var_url_path <- "/user/login" diff --git a/samples/client/petstore/R-httr2/docs/PetApi.md b/samples/client/petstore/R-httr2/docs/PetApi.md index 35922fbc742..64b08e54db0 100644 --- a/samples/client/petstore/R-httr2/docs/PetApi.md +++ b/samples/client/petstore/R-httr2/docs/PetApi.md @@ -213,8 +213,6 @@ var_tags <- list("inner_example") # array[character] | Tags to filter by # Finds Pets by tags api_instance <- PetApi$new() -# Configure OAuth2 access token for authorization: petstore_auth -api_instance$api_client$access_token <- Sys.getenv("ACCESS_TOKEN") result <- tryCatch( # to save the result into a file, simply add the optional `data_file` parameter, e.g. # api_instance$find_pets_by_tags(var_tags, data_file = "result.txt"), @@ -247,7 +245,7 @@ Name | Type | Description | Notes ### Authorization -[petstore_auth](../README.md#petstore_auth) +No authorization required ### HTTP request headers diff --git a/samples/client/petstore/R/R/pet_api.R b/samples/client/petstore/R/R/pet_api.R index e14189542b9..df3e541a33d 100644 --- a/samples/client/petstore/R/R/pet_api.R +++ b/samples/client/petstore/R/R/pet_api.R @@ -395,9 +395,6 @@ #' #Finds Pets by tags #' api_instance <- PetApi$new() #' -#' # Configure OAuth2 access token for authorization: petstore_auth -#' api_instance$api_client$access_token <- Sys.getenv("ACCESS_TOKEN") -#' #' result <- tryCatch( #' #' # to save the result into a file, simply add the optional `data_file` parameter, e.g. @@ -944,6 +941,7 @@ PetApi <- R6::R6Class( } + # explore for (query_item in `status`) { query_params[["status"]] <- c(query_params[["status"]], list(`status` = query_item)) } @@ -1064,14 +1062,10 @@ PetApi <- R6::R6Class( } - for (query_item in `tags`) { - query_params[["tags"]] <- c(query_params[["tags"]], list(`tags` = query_item)) - } + # no explore + query_params[["tags"]] <- I(paste(lapply(`tags`, URLencode, reserved = TRUE), collapse = ",")) local_var_url_path <- "/pet/findByTags" - # OAuth-related settings - is_oauth <- TRUE - oauth_scopes <- "read:pets" # The Accept request HTTP header local_var_accepts <- list("application/xml", "application/json") diff --git a/samples/client/petstore/R/R/user_api.R b/samples/client/petstore/R/R/user_api.R index c29e46736b4..28fb0ee46c4 100644 --- a/samples/client/petstore/R/R/user_api.R +++ b/samples/client/petstore/R/R/user_api.R @@ -1071,9 +1071,9 @@ UserApi <- R6::R6Class( } - query_params["username"] <- `username` + query_params[["username"]] <- `username` - query_params["password"] <- `password` + query_params[["password"]] <- `password` local_var_url_path <- "/user/login" diff --git a/samples/client/petstore/R/docs/PetApi.md b/samples/client/petstore/R/docs/PetApi.md index fa212fa2fda..2dce1e400dd 100644 --- a/samples/client/petstore/R/docs/PetApi.md +++ b/samples/client/petstore/R/docs/PetApi.md @@ -213,8 +213,6 @@ var_tags <- list("inner_example") # array[character] | Tags to filter by # Finds Pets by tags api_instance <- PetApi$new() -# Configure OAuth2 access token for authorization: petstore_auth -api_instance$api_client$access_token <- Sys.getenv("ACCESS_TOKEN") result <- tryCatch( # to save the result into a file, simply add the optional `data_file` parameter, e.g. # api_instance$FindPetsByTags(var_tags, data_file = "result.txt"), @@ -247,7 +245,7 @@ Name | Type | Description | Notes ### Authorization -[petstore_auth](../README.md#petstore_auth) +No authorization required ### HTTP request headers