Skip to content

Commit 815a732

Browse files
authored
[R] add null checks to nullable api parameters (#21629)
* [R] check optional parametrs for null before evaluating param conditions * update petstore * handle isNullable when checking api parameters * update samples * allow not-nullable parameters to be missing * update samples * samples
1 parent 1a178ae commit 815a732

File tree

18 files changed

+777
-23
lines changed

18 files changed

+777
-23
lines changed

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

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,21 @@
206206
207207
{{/requiredParams}}
208208
{{#allParams}}
209+
{{^isNullable}}
210+
if (!missing(`{{paramName}}`) && is.null(`{{paramName}}`)) {
211+
{{#useDefaultExceptionHandling}}
212+
stop("Invalid value for `{{paramName}}` when calling {{classname}}${{operationId}}, `{{paramName}}` is not nullable")
213+
{{/useDefaultExceptionHandling}}
214+
{{#useRlangExceptionHandling}}
215+
rlang::abort(message = "Invalid value for `{{paramName}}` when calling {{classname}}${{operationId}}, `{{paramName}}` is not nullable",
216+
.subclass = "ApiException",
217+
ApiException = ApiException$new(status = 0,
218+
reason = "Invalid value for `{{paramName}}` when calling {{classname}}${{operationId}}, `{{paramName}}` is not nullable"))
219+
{{/useRlangExceptionHandling}}
220+
}
221+
{{/isNullable}}
209222
{{#maxLength}}
210-
if (nchar(`{{paramName}}`) > {{maxLength}}) {
223+
if (!is.null(`{{paramName}}`) && nchar(`{{paramName}}`) > {{maxLength}}) {
211224
{{#useDefaultExceptionHandling}}
212225
stop("Invalid length for `{{paramName}}` when calling {{classname}}${{operationId}}, must be smaller than or equal to {{maxLength}}.")
213226
{{/useDefaultExceptionHandling}}
@@ -220,7 +233,7 @@
220233
}
221234
{{/maxLength}}
222235
{{#minLength}}
223-
if (nchar(`{{paramName}}`) < {{minLength}}) {
236+
if (!is.null(`{{paramName}}`) && nchar(`{{paramName}}`) < {{minLength}}) {
224237
{{#useDefaultExceptionHandling}}
225238
stop("Invalid length for `{{paramName}}` when calling {{classname}}${{operationId}}, must be bigger than or equal to {{minLength}}.")
226239
{{/useDefaultExceptionHandling}}
@@ -233,7 +246,7 @@
233246
}
234247
{{/minLength}}
235248
{{#maximum}}
236-
if (`{{paramName}}` >{{#exclusiveMaximum}}={{/exclusiveMaximum}} {{maximum}}) {
249+
if (!is.null(`{{paramName}}`) && `{{paramName}}` > {{#exclusiveMaximum}}={{/exclusiveMaximum}} {{maximum}}) {
237250
{{#useDefaultExceptionHandling}}
238251
stop("Invalid value for `{{paramName}}` when calling {{classname}}${{operationId}}, must be smaller than {{^exclusiveMaximum}}or equal to {{/exclusiveMaximum}}{{maximum}}.")
239252
{{/useDefaultExceptionHandling}}
@@ -246,7 +259,7 @@
246259
}
247260
{{/maximum}}
248261
{{#minimum}}
249-
if (`{{paramName}}` <{{#exclusiveMinimum}}={{/exclusiveMinimum}} {{minimum}}) {
262+
if (!is.null(`{{paramName}}`) && `{{paramName}}` < {{#exclusiveMinimum}}={{/exclusiveMinimum}} {{minimum}}) {
250263
{{#useDefaultExceptionHandling}}
251264
stop("Invalid value for `{{paramName}}` when calling {{classname}}${{operationId}}, must be bigger than {{^exclusiveMinimum}}or equal to {{/exclusiveMinimum}}{{minimum}}.")
252265
{{/useDefaultExceptionHandling}}
@@ -259,7 +272,7 @@
259272
}
260273
{{/minimum}}
261274
{{#pattern}}
262-
if (!str_detect(`{{paramName}}`, "{{{pattern}}}")) {
275+
if (!is.null(`{{paramName}}`) && !stringr::str_detect(`{{paramName}}`, "{{{pattern}}}")) {
263276
{{#useDefaultExceptionHandling}}
264277
stop("Invalid value for `{{paramName}}` when calling {{classname}}${{operationId}}, must conform to the pattern {{{pattern}}}.")
265278
{{/useDefaultExceptionHandling}}
@@ -272,7 +285,7 @@
272285
}
273286
{{/pattern}}
274287
{{#maxItems}}
275-
if (length(`{{paramName}}`) > {{maxItems}}) {
288+
if (!is.null(`{{paramName}}`) && length(`{{paramName}}`) > {{maxItems}}) {
276289
{{#useDefaultExceptionHandling}}
277290
stop("Invalid length for `{{paramName}}` when calling {{classname}}${{operationId}}, number of items must be less than or equal to {{maxItems}}.")
278291
{{/useDefaultExceptionHandling}}
@@ -285,7 +298,7 @@
285298
}
286299
{{/maxItems}}
287300
{{#minItems}}
288-
if (length(`{{paramName}}`) < {{minItems}}) {
301+
if (!is.null(`{{paramName}}`) && length(`{{paramName}}`) < {{minItems}}) {
289302
{{#useDefaultExceptionHandling}}
290303
stop("Invalid length for `{{paramName}}` when calling {{classname}}${{operationId}}, number of items must be greater than or equal to {{minItems}}.")
291304
{{/useDefaultExceptionHandling}}
@@ -307,7 +320,7 @@
307320
{{#isArray}}
308321
{{#uniqueItems}}
309322
# check if items are unique
310-
if (!identical(`{{{paramName}}}`, unique(`{{{paramName}}}`))) {
323+
if (!is.null(`{{paramName}}`) && !identical(`{{{paramName}}}`, unique(`{{{paramName}}}`))) {
311324
{{#useDefaultExceptionHandling}}
312325
stop("Invalid value for {{{paramName}}} when calling {{classname}}${{operationId}}. Items must be unique.")
313326
{{/useDefaultExceptionHandling}}

samples/client/echo_api/r/R/body_api.R

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,9 @@ BodyApi <- R6::R6Class(
300300
oauth_scopes <- NULL
301301
is_oauth <- FALSE
302302

303+
if (!missing(`body`) && is.null(`body`)) {
304+
stop("Invalid value for `body` when calling BodyApi$TestBodyApplicationOctetstreamBinary, `body` is not nullable")
305+
}
303306

304307
if (!is.null(`body`)) {
305308
local_var_body <- `body`$toJSONString()
@@ -400,6 +403,9 @@ BodyApi <- R6::R6Class(
400403
stop("Missing required parameter `files`.")
401404
}
402405

406+
if (!missing(`files`) && is.null(`files`)) {
407+
stop("Invalid value for `files` when calling BodyApi$TestBodyMultipartFormdataArrayOfBinary, `files` is not nullable")
408+
}
403409

404410
file_params["files"] <- httr::upload_file(`files`)
405411
local_var_url_path <- "/body/application/octetstream/array_of_binary"
@@ -491,6 +497,9 @@ BodyApi <- R6::R6Class(
491497
oauth_scopes <- NULL
492498
is_oauth <- FALSE
493499

500+
if (!missing(`my_file`) && is.null(`my_file`)) {
501+
stop("Invalid value for `my_file` when calling BodyApi$TestBodyMultipartFormdataSingleBinary, `my_file` is not nullable")
502+
}
494503

495504
file_params["my-file"] <- httr::upload_file(`my_file`)
496505
local_var_url_path <- "/body/application/octetstream/single_binary"
@@ -582,6 +591,9 @@ BodyApi <- R6::R6Class(
582591
oauth_scopes <- NULL
583592
is_oauth <- FALSE
584593

594+
if (!missing(`pet`) && is.null(`pet`)) {
595+
stop("Invalid value for `pet` when calling BodyApi$TestEchoBodyAllOfPet, `pet` is not nullable")
596+
}
585597

586598
if (!is.null(`pet`)) {
587599
local_var_body <- `pet`$toJSONString()
@@ -678,6 +690,9 @@ BodyApi <- R6::R6Class(
678690
oauth_scopes <- NULL
679691
is_oauth <- FALSE
680692

693+
if (!missing(`body`) && is.null(`body`)) {
694+
stop("Invalid value for `body` when calling BodyApi$TestEchoBodyFreeFormObjectResponseString, `body` is not nullable")
695+
}
681696

682697
if (!is.null(`body`)) {
683698
local_var_body <- `body`$toJSONString()
@@ -774,6 +789,9 @@ BodyApi <- R6::R6Class(
774789
oauth_scopes <- NULL
775790
is_oauth <- FALSE
776791

792+
if (!missing(`pet`) && is.null(`pet`)) {
793+
stop("Invalid value for `pet` when calling BodyApi$TestEchoBodyPet, `pet` is not nullable")
794+
}
777795

778796
if (!is.null(`pet`)) {
779797
local_var_body <- `pet`$toJSONString()
@@ -870,6 +888,9 @@ BodyApi <- R6::R6Class(
870888
oauth_scopes <- NULL
871889
is_oauth <- FALSE
872890

891+
if (!missing(`pet`) && is.null(`pet`)) {
892+
stop("Invalid value for `pet` when calling BodyApi$TestEchoBodyPetResponseString, `pet` is not nullable")
893+
}
873894

874895
if (!is.null(`pet`)) {
875896
local_var_body <- `pet`$toJSONString()
@@ -966,6 +987,9 @@ BodyApi <- R6::R6Class(
966987
oauth_scopes <- NULL
967988
is_oauth <- FALSE
968989

990+
if (!missing(`body`) && is.null(`body`)) {
991+
stop("Invalid value for `body` when calling BodyApi$TestEchoBodyStringEnum, `body` is not nullable")
992+
}
969993

970994
if (!is.null(`body`)) {
971995
local_var_body <- `body`$toJSONString()
@@ -1062,6 +1086,9 @@ BodyApi <- R6::R6Class(
10621086
oauth_scopes <- NULL
10631087
is_oauth <- FALSE
10641088

1089+
if (!missing(`tag`) && is.null(`tag`)) {
1090+
stop("Invalid value for `tag` when calling BodyApi$TestEchoBodyTagResponseString, `tag` is not nullable")
1091+
}
10651092

10661093
if (!is.null(`tag`)) {
10671094
local_var_body <- `tag`$toJSONString()

samples/client/echo_api/r/R/form_api.R

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,17 @@ FormApi <- R6::R6Class(
127127
oauth_scopes <- NULL
128128
is_oauth <- FALSE
129129

130+
if (!missing(`integer_form`) && is.null(`integer_form`)) {
131+
stop("Invalid value for `integer_form` when calling FormApi$TestFormIntegerBooleanString, `integer_form` is not nullable")
132+
}
130133

134+
if (!missing(`boolean_form`) && is.null(`boolean_form`)) {
135+
stop("Invalid value for `boolean_form` when calling FormApi$TestFormIntegerBooleanString, `boolean_form` is not nullable")
136+
}
131137

138+
if (!missing(`string_form`) && is.null(`string_form`)) {
139+
stop("Invalid value for `string_form` when calling FormApi$TestFormIntegerBooleanString, `string_form` is not nullable")
140+
}
132141

133142
form_params["integer_form"] <- `integer_form`
134143
form_params["boolean_form"] <- `boolean_form`
@@ -226,6 +235,9 @@ FormApi <- R6::R6Class(
226235
stop("Missing required parameter `marker`.")
227236
}
228237

238+
if (!missing(`marker`) && is.null(`marker`)) {
239+
stop("Invalid value for `marker` when calling FormApi$TestFormObjectMultipart, `marker` is not nullable")
240+
}
229241

230242
form_params["marker"] <- `marker`
231243
local_var_url_path <- "/form/object/multipart"
@@ -327,11 +339,29 @@ FormApi <- R6::R6Class(
327339
oauth_scopes <- NULL
328340
is_oauth <- FALSE
329341

342+
if (!missing(`form1`) && is.null(`form1`)) {
343+
stop("Invalid value for `form1` when calling FormApi$TestFormOneof, `form1` is not nullable")
344+
}
330345

346+
if (!missing(`form2`) && is.null(`form2`)) {
347+
stop("Invalid value for `form2` when calling FormApi$TestFormOneof, `form2` is not nullable")
348+
}
331349

350+
if (!missing(`form3`) && is.null(`form3`)) {
351+
stop("Invalid value for `form3` when calling FormApi$TestFormOneof, `form3` is not nullable")
352+
}
332353

354+
if (!missing(`form4`) && is.null(`form4`)) {
355+
stop("Invalid value for `form4` when calling FormApi$TestFormOneof, `form4` is not nullable")
356+
}
333357

358+
if (!missing(`id`) && is.null(`id`)) {
359+
stop("Invalid value for `id` when calling FormApi$TestFormOneof, `id` is not nullable")
360+
}
334361

362+
if (!missing(`name`) && is.null(`name`)) {
363+
stop("Invalid value for `name` when calling FormApi$TestFormOneof, `name` is not nullable")
364+
}
335365

336366
form_params["form1"] <- `form1`
337367
form_params["form2"] <- `form2`

samples/client/echo_api/r/R/header_api.R

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,25 @@ HeaderApi <- R6::R6Class(
100100
oauth_scopes <- NULL
101101
is_oauth <- FALSE
102102

103+
if (!missing(`integer_header`) && is.null(`integer_header`)) {
104+
stop("Invalid value for `integer_header` when calling HeaderApi$TestHeaderIntegerBooleanStringEnums, `integer_header` is not nullable")
105+
}
103106

107+
if (!missing(`boolean_header`) && is.null(`boolean_header`)) {
108+
stop("Invalid value for `boolean_header` when calling HeaderApi$TestHeaderIntegerBooleanStringEnums, `boolean_header` is not nullable")
109+
}
104110

111+
if (!missing(`string_header`) && is.null(`string_header`)) {
112+
stop("Invalid value for `string_header` when calling HeaderApi$TestHeaderIntegerBooleanStringEnums, `string_header` is not nullable")
113+
}
105114

115+
if (!missing(`enum_nonref_string_header`) && is.null(`enum_nonref_string_header`)) {
116+
stop("Invalid value for `enum_nonref_string_header` when calling HeaderApi$TestHeaderIntegerBooleanStringEnums, `enum_nonref_string_header` is not nullable")
117+
}
106118

119+
if (!missing(`enum_ref_string_header`) && is.null(`enum_ref_string_header`)) {
120+
stop("Invalid value for `enum_ref_string_header` when calling HeaderApi$TestHeaderIntegerBooleanStringEnums, `enum_ref_string_header` is not nullable")
121+
}
107122

108123
header_params["integer_header"] <- `integer_header`
109124

samples/client/echo_api/r/R/path_api.R

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,21 @@ PathApi <- R6::R6Class(
113113
stop("Missing required parameter `enum_ref_string_path`.")
114114
}
115115

116+
if (!missing(`path_string`) && is.null(`path_string`)) {
117+
stop("Invalid value for `path_string` when calling PathApi$TestsPathStringPathStringIntegerPathIntegerEnumNonrefStringPathEnumRefStringPath, `path_string` is not nullable")
118+
}
116119

120+
if (!missing(`path_integer`) && is.null(`path_integer`)) {
121+
stop("Invalid value for `path_integer` when calling PathApi$TestsPathStringPathStringIntegerPathIntegerEnumNonrefStringPathEnumRefStringPath, `path_integer` is not nullable")
122+
}
117123

124+
if (!missing(`enum_nonref_string_path`) && is.null(`enum_nonref_string_path`)) {
125+
stop("Invalid value for `enum_nonref_string_path` when calling PathApi$TestsPathStringPathStringIntegerPathIntegerEnumNonrefStringPathEnumRefStringPath, `enum_nonref_string_path` is not nullable")
126+
}
118127

128+
if (!missing(`enum_ref_string_path`) && is.null(`enum_ref_string_path`)) {
129+
stop("Invalid value for `enum_ref_string_path` when calling PathApi$TestsPathStringPathStringIntegerPathIntegerEnumNonrefStringPathEnumRefStringPath, `enum_ref_string_path` is not nullable")
130+
}
119131

120132
local_var_url_path <- "/path/string/{path_string}/integer/{path_integer}/{enum_nonref_string_path}/{enum_ref_string_path}"
121133
if (!missing(`path_string`)) {

0 commit comments

Comments
 (0)