Skip to content

Commit 7d768f2

Browse files
authored
[R] add error object type support (#12402)
* use rlang as exception in the petstore test * add errorObject support * fix method name, use ModelApiRespeonse * update samples * update doc * fix api exception
1 parent 45baa5e commit 7d768f2

8 files changed

Lines changed: 126 additions & 65 deletions

File tree

bin/configs/r-client.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ additionalProperties:
88
exceptionPackage: rlang
99
useRlangExceptionHandling: true
1010
returnExceptionOnFailure: true
11+
errorObjectType: "ModelApiResponse"

docs/generators/r.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
1818

1919
| Option | Description | Values | Default |
2020
| ------ | ----------- | ------ | ------- |
21+
|errorObjectType|Error object type.| |null|
2122
|exceptionPackage|Specify the exception handling package|<dl><dt>**default**</dt><dd>Use stop() for raising exceptions.</dd><dt>**rlang**</dt><dd>Use rlang package for exceptions.</dd></dl>|default|
2223
|hideGenerationTimestamp|Hides the generation timestamp when files are generated.| |true|
2324
|packageName|R package name (convention: lowercase).| |openapi|

modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConstants.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,4 +398,7 @@ public static enum ENUM_PROPERTY_NAMING_TYPE {camelCase, PascalCase, snake_case,
398398
public static final String USE_ONEOF_DISCRIMINATOR_LOOKUP_DESC = "Use the discriminator's mapping in oneOf to speed up the model lookup. IMPORTANT: Validation (e.g. one and only one match in oneOf's schemas) will be skipped.";
399399
public static final String INIT_REQUIRED_VARS = "initRequiredVars";
400400
public static final String INIT_REQUIRED_VARS_DESC = "If set to true then the required variables are included as positional arguments in __init__ and _from_openapi_data methods. Note: this can break some composition use cases. To learn more read PR #8802.";
401+
402+
public static final String ERROR_OBJECT_TYPE = "errorObjectType";
403+
401404
}

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RClientCodegen.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ public class RClientCodegen extends DefaultCodegen implements CodegenConfig {
6666

6767
protected boolean useDefaultExceptionHandling = false;
6868
protected boolean useRlangExceptionHandling = false;
69+
protected String errorObjectType;
6970

7071
public CodegenType getTag() {
7172
return CodegenType.CLIENT;
@@ -181,6 +182,8 @@ public RClientCodegen() {
181182
exceptionPackage.setEnum(exceptionPackages);
182183
exceptionPackage.setDefault(DEFAULT);
183184
cliOptions.add(exceptionPackage);
185+
186+
cliOptions.add(CliOption.newString(CodegenConstants.ERROR_OBJECT_TYPE, "Error object type."));
184187
}
185188

186189
@Override
@@ -213,6 +216,11 @@ public void processOpts() {
213216
setExceptionPackageToUse(DEFAULT);
214217
}
215218

219+
if (additionalProperties.containsKey(CodegenConstants.ERROR_OBJECT_TYPE)) {
220+
this.setErrorObjectType(additionalProperties.get(CodegenConstants.ERROR_OBJECT_TYPE).toString());
221+
}
222+
additionalProperties.put(CodegenConstants.ERROR_OBJECT_TYPE, errorObjectType);
223+
216224
additionalProperties.put(CodegenConstants.PACKAGE_NAME, packageName);
217225
additionalProperties.put(CodegenConstants.PACKAGE_VERSION, packageVersion);
218226
additionalProperties.put(CodegenConstants.EXCEPTION_ON_FAILURE, returnExceptionOnFailure);
@@ -500,6 +508,10 @@ public void setExceptionPackageToUse(String exceptionPackage) {
500508
}
501509
}
502510

511+
public void setErrorObjectType(final String errorObjectType) {
512+
this.errorObjectType = errorObjectType;
513+
}
514+
503515
@Override
504516
public String escapeQuotationMark(String input) {
505517
// remove " to avoid code injection

modules/openapi-generator/src/main/resources/r/api_exception.mustache

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
#' @field reason Reason of the ApiException
99
#' @field body Body of the http response
1010
#' @field headers Headers of the http response
11+
{{#errorObjectType}}
12+
#' @field errorObject error object type
13+
{{/errorObjectType}}
1114
#' @export
1215
ApiException <- R6::R6Class(
1316
"ApiException",
@@ -16,6 +19,9 @@ ApiException <- R6::R6Class(
1619
reason = NULL,
1720
body = NULL,
1821
headers = NULL,
22+
{{#errorObjectType}}
23+
errorObject = NULL,
24+
{{/errorObjectType}}
1925
#' Initialize a new ApiException class.
2026
#'
2127
#' @description
@@ -35,11 +41,17 @@ ApiException <- R6::R6Class(
3541
self$body <- errorMsg
3642
self$headers <- http_response$headers
3743
self$reason <- httr::http_status(http_response)$reason
44+
{{#errorObjectType}}
45+
self$errorObject <- {{errorObjectType}}$new()$fromJSONString(content(http_response, "text"))
46+
{{/errorObjectType}}
3847
} else {
3948
self$status <- status
4049
self$reason <- reason
4150
self$body <- NULL
4251
self$headers <- NULL
52+
{{#errorObjectType}}
53+
self$errorObject <- NULL
54+
{{/errorObjectType}}
4355
}
4456
},
4557
#' Returns the string format of ApiException.
@@ -63,6 +75,12 @@ ApiException <- R6::R6Class(
6375
errorMsg <- paste(errorMsg, "Body : ", "\n", sep = "")
6476
errorMsg <- paste(errorMsg, self$body,"\n")
6577
}
78+
{{#errorObjectType}}
79+
if (!is.null(self$errorObject)) {
80+
errorMsg <- paste(errorMsg, "Error object : ", "\n", sep = "")
81+
errorMsg <- paste(errorMsg, self$errorObject$toJSONString(),"\n")
82+
}
83+
{{/errorObjectType}}
6684
errorMsg
6785
}
6886
)

samples/client/petstore/R/R/api_exception.R

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#' @field reason Reason of the ApiException
1515
#' @field body Body of the http response
1616
#' @field headers Headers of the http response
17+
#' @field errorObject error object type
1718
#' @export
1819
ApiException <- R6::R6Class(
1920
"ApiException",
@@ -22,6 +23,7 @@ ApiException <- R6::R6Class(
2223
reason = NULL,
2324
body = NULL,
2425
headers = NULL,
26+
errorObject = NULL,
2527
#' Initialize a new ApiException class.
2628
#'
2729
#' @description
@@ -41,11 +43,13 @@ ApiException <- R6::R6Class(
4143
self$body <- errorMsg
4244
self$headers <- http_response$headers
4345
self$reason <- httr::http_status(http_response)$reason
46+
self$errorObject <- ModelApiResponse$new()$fromJSONString(content(http_response, "text"))
4447
} else {
4548
self$status <- status
4649
self$reason <- reason
4750
self$body <- NULL
4851
self$headers <- NULL
52+
self$errorObject <- NULL
4953
}
5054
},
5155
#' Returns the string format of ApiException.
@@ -69,6 +73,10 @@ ApiException <- R6::R6Class(
6973
errorMsg <- paste(errorMsg, "Body : ", "\n", sep = "")
7074
errorMsg <- paste(errorMsg, self$body,"\n")
7175
}
76+
if (!is.null(self$errorObject)) {
77+
errorMsg <- paste(errorMsg, "Error object : ", "\n", sep = "")
78+
errorMsg <- paste(errorMsg, self$errorObject$toJSONString(),"\n")
79+
}
7280
errorMsg
7381
}
7482
)

samples/client/petstore/R/test_petstore.R

Lines changed: 70 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -2,71 +2,76 @@
22
install.packages("petstore_1.0.0.tar.gz",repos=NULL, type="source")
33
library(petstore)
44

5-
var_pet_id <- 56 # integer | ID of pet to return
5+
errorMsg <- "{\"code\":1,\"type\":\"error\",\"message\":\"Pet not found\"}"
6+
#errorMsg <- '{"code": 404, "message": "Not found"}'
7+
a <- ModelApiResponse$new()$fromJSONString(errorMsg)
8+
dput(a)
69

7-
#Find pet by ID
8-
#api_instance <- PetApi$new()
9-
## Configure API key authorization: api_key
10-
#api_instance$api_client$api_keys['api_key'] <- 'TODO_YOUR_API_KEY';
11-
#result <- tryCatch(
12-
# api_instance$GetPetById(var_pet_id),
13-
# ApiException = function(ex) ex
14-
# )
15-
## In case of error, print the error object
16-
#if(!is.null(result$ApiException)) {
17-
# cat(result$ApiException$toString())
18-
#} else {
19-
# # deserialized response object
20-
# response.object <- result$content
21-
# # response headers
22-
# response.headers <- result$response$headers
23-
# # response status code
24-
# response.status.code <- result$response$status_code
25-
#}
26-
27-
json2 <-
28-
'{"name": "pet", "photoUrls" : ["http://a.com", "http://b.com"]}'
29-
30-
json <-
31-
'[
32-
{"Name" : "Mario", "Age" : 32, "Occupation" : "Plumber"},
33-
{"Name" : "Peach", "Age" : 21, "Occupation" : "Princess"},
34-
{},
35-
{"Name" : "Bowser", "Occupation" : "Koopa"}
36-
]'
37-
38-
39-
#Pet$public_methods
40-
#Pet$public_methods$fromJSON(json)
41-
#Pet$public_methods$toJson()
42-
#Pet$public_methods$validateJSON(json2)
43-
#Pet$public_methods$validateJson(json)
44-
#Pet$my_static_method <- function(x) { x + 2}
45-
#Pet$public_methods$my_static_method(1)
46-
47-
basque_pig_json <-
48-
'{"className2": "BasquePig", "color": "red"}'
49-
50-
danish_pig_json <-
51-
'{"className2": "DanishPig", "size": 7}'
52-
53-
wrong_json <-
54-
'[
55-
{"Name" : "Tom", "Age" : 32, "Occupation" : "Consultant"},
56-
{},
57-
{"Name" : "Ada", "Occupation" : "Engineer"}
58-
]'
59-
60-
print("==========")
61-
pig <- Pig$new()
62-
basque_pig <- pig$fromJSON(basque_pig_json)
63-
#print(basque_pig$actual_instance$color)
64-
#expect_equal(basque_pig$actual_type, "BasquePig")
65-
pig$fromJSON(danish_pig_json)
66-
#pig$fromJSON(wrong_json)
67-
pig$toJSON()
68-
69-
#d <- DanishPig$new()
70-
#dp <- d$validateJSON(danish_pig_json)
10+
var_pet_id <- 1231256 # integer | ID of pet to return
7111

12+
#Find pet by ID
13+
api_instance <- PetApi$new()
14+
# Configure API key authorization: api_key
15+
api_instance$api_client$api_keys['api_key'] <- 'TODO_YOUR_API_KEY';
16+
result <- tryCatch(
17+
api_instance$GetPetById(var_pet_id),
18+
ApiException = function(ex) ex
19+
)
20+
# In case of error, print the error object
21+
if(!is.null(result$ApiException)) {
22+
cat(result$ApiException$toString())
23+
} else {
24+
# deserialized response object
25+
response.object <- result$content
26+
# response headers
27+
response.headers <- result$response$headers
28+
# response status code
29+
response.status.code <- result$response$status_code
30+
}
7231

32+
#json2 <-
33+
#'{"name": "pet", "photoUrls" : ["http://a.com", "http://b.com"]}'
34+
#
35+
#json <-
36+
#'[
37+
# {"Name" : "Mario", "Age" : 32, "Occupation" : "Plumber"},
38+
# {"Name" : "Peach", "Age" : 21, "Occupation" : "Princess"},
39+
# {},
40+
# {"Name" : "Bowser", "Occupation" : "Koopa"}
41+
#]'
42+
#
43+
#
44+
##Pet$public_methods
45+
##Pet$public_methods$fromJSON(json)
46+
##Pet$public_methods$toJson()
47+
##Pet$public_methods$validateJSON(json2)
48+
##Pet$public_methods$validateJson(json)
49+
##Pet$my_static_method <- function(x) { x + 2}
50+
##Pet$public_methods$my_static_method(1)
51+
#
52+
# basque_pig_json <-
53+
# '{"className2": "BasquePig", "color": "red"}'
54+
#
55+
# danish_pig_json <-
56+
# '{"className2": "DanishPig", "size": 7}'
57+
#
58+
# wrong_json <-
59+
# '[
60+
# {"Name" : "Tom", "Age" : 32, "Occupation" : "Consultant"},
61+
# {},
62+
# {"Name" : "Ada", "Occupation" : "Engineer"}
63+
# ]'
64+
#
65+
# print("==========")
66+
# pig <- Pig$new()
67+
# basque_pig <- pig$fromJSON(basque_pig_json)
68+
# #print(basque_pig$actual_instance$color)
69+
# #expect_equal(basque_pig$actual_type, "BasquePig")
70+
# pig$fromJSON(danish_pig_json)
71+
# #pig$fromJSON(wrong_json)
72+
# pig$toJSON()
73+
#
74+
# #d <- DanishPig$new()
75+
# #dp <- d$validateJSON(danish_pig_json)
76+
#
77+
#

samples/client/petstore/R/tests/testthat/test_petstore.R

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,19 @@ test_that("GetPetById", {
9292
)
9393
})
9494

95+
#test_that("test GetPetById exception", {
96+
# # test exception
97+
# result <- tryCatch(petApi$GetPetById(98765), # petId not exist
98+
# error = function(ex) ex
99+
# )
100+
#
101+
# expect_true(!is.null(result))
102+
# #expect_equal(result$toString(),"")
103+
# expect_equal(result, "1")
104+
# #expect_equal(result$ApiException$errorObject$code, 1)
105+
# #expect_equal(response$name, "name_test")
106+
#})
107+
95108
test_that("GetPetById with data_file", {
96109
# test to ensure json is saved to the file `get_pet_by_id.json`
97110
pet_response <- pet_api$GetPetById(pet_id, data_file = "get_pet_by_id.json")

0 commit comments

Comments
 (0)