Skip to content

Commit 7916f2f

Browse files
sylvainmoindronjimschubert
authored andcommitted
[kotlin-spring] add reactive behavior via Kotlin coroutines (#2934)
* kotlin spring : add reactivity via kotlin's coroutines * add kotlin spring boot reactive samples * bug : fix spring version and import for coroutines * remove exception handler for reactive (webflux doesn't support it) * add spring milestone repository to maven pom * add reactive type for list in Api and ApiImpl methodes for mathching body responsive parameter * fix baseType for ArraySchema * regenerate samples * updating documentation
1 parent b74fa44 commit 7916f2f

File tree

146 files changed

+3078
-268
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

146 files changed

+3078
-268
lines changed

bin/kotlin-springboot-petstore-all.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/bin/sh
2+
3+
./bin/kotlin-springboot-petstore-server.sh
4+
./bin/kotlin-springboot-petstore-server-reactive.sh
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#!/bin/sh
2+
3+
SCRIPT="$0"
4+
echo "# START SCRIPT: $SCRIPT"
5+
6+
while [ -h "$SCRIPT" ] ; do
7+
ls=$(ls -ld "$SCRIPT")
8+
link=$(expr "$ls" : '.*-> \(.*\)$')
9+
if expr "$link" : '/.*' > /dev/null; then
10+
SCRIPT="$link"
11+
else
12+
SCRIPT=$(dirname "$SCRIPT")/"$link"
13+
fi
14+
done
15+
16+
if [ ! -d "${APP_DIR}" ]; then
17+
APP_DIR=$(dirname "$SCRIPT")/..
18+
APP_DIR=$(cd "${APP_DIR}"; pwd)
19+
fi
20+
21+
executable="./modules/openapi-generator-cli/target/openapi-generator-cli.jar"
22+
23+
if [ ! -f "$executable" ]
24+
then
25+
mvn clean package
26+
fi
27+
28+
export JAVA_OPTS="${JAVA_OPTS} -Xmx1024M -DloggerPath=conf/log4j.properties"
29+
ags="$@ generate -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -t modules/openapi-generator/src/main/resources/kotlin-spring -g kotlin-spring -o samples/server/petstore/kotlin-springboot-reactive --additional-properties=library=spring-boot,beanValidations=true,swaggerAnnotations=true,serviceImplementation=true,reactive=true"
30+
31+
echo "Cleaning previously generated files if any from samples/server/petstore/kotlin-springboot-reactive"
32+
rm -rf samples/server/petstore/kotlin-springboot-reactive
33+
34+
echo "Generating Kotling Spring Boot reactive server..."
35+
java $JAVA_OPTS -jar $executable $ags
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/bin/sh
2+
3+
./bin/openapi3/kotlin-springboot-petstore-server.sh
4+
./bin/openapi3/kotlin-springboot-petstore-server-reactive.sh
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#!/bin/sh
2+
3+
SCRIPT="$0"
4+
echo "# START SCRIPT: $SCRIPT"
5+
6+
while [ -h "$SCRIPT" ] ; do
7+
ls=$(ls -ld "$SCRIPT")
8+
link=$(expr "$ls" : '.*-> \(.*\)$')
9+
if expr "$link" : '/.*' > /dev/null; then
10+
SCRIPT="$link"
11+
else
12+
SCRIPT=$(dirname "$SCRIPT")/"$link"
13+
fi
14+
done
15+
16+
if [ ! -d "${APP_DIR}" ]; then
17+
APP_DIR=$(dirname "$SCRIPT")/..
18+
APP_DIR=$(cd "${APP_DIR}"; pwd)
19+
fi
20+
21+
executable="./modules/openapi-generator-cli/target/openapi-generator-cli.jar"
22+
23+
if [ ! -f "$executable" ]
24+
then
25+
mvn clean package
26+
fi
27+
28+
export JAVA_OPTS="${JAVA_OPTS} -Xmx1024M -DloggerPath=conf/log4j.properties"
29+
ags="$@ generate -i modules/openapi-generator/src/test/resources/3_0/petstore.yaml -t modules/openapi-generator/src/main/resources/kotlin-spring -g kotlin-spring -o samples/server/openapi3/petstore/kotlin-springboot-reactive --additional-properties=library=spring-boot,beanValidations=true,swaggerAnnotations=true,serviceImplementation=true,reactive=true"
30+
31+
echo "Cleaning previously generated files if any from samples/server/openapi3/petstore/kotlin-springboot-reactive"
32+
rm -rf samples/server/openapi3/petstore/kotlin-springboot-reactive
33+
34+
echo "Generating Kotling Spring Boot server..."
35+
java $JAVA_OPTS -jar $executable $ags

docs/generators/kotlin-spring.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@ sidebar_label: kotlin-spring
2020
|serverPort|configuration the port in which the sever is to run on| |8080|
2121
|modelPackage|model package for generated code| |org.openapitools.model|
2222
|apiPackage|api package for generated code| |org.openapitools.api|
23-
|exceptionHandler|generate default global exception handlers| |true|
23+
|exceptionHandler|generate default global exception handlers (not compatible with reactive. enabling reactive will disable exceptionHandler )| |true|
2424
|gradleBuildFile|generate a gradle build file using the Kotlin DSL| |true|
2525
|swaggerAnnotations|generate swagger annotations to go alongside controllers and models| |false|
2626
|serviceInterface|generate service interfaces to go alongside controllers. In most cases this option would be used to update an existing project, so not to override implementations. Useful to help facilitate the generation gap pattern| |false|
2727
|serviceImplementation|generate stub service implementations that extends service interfaces. If this is set to true service interfaces will also be generated| |false|
2828
|useBeanValidation|Use BeanValidation API annotations to validate data types| |true|
29+
|reactive|use coroutines for reactive behavior| |false|
2930
|library|library template (sub-template)|<dl><dt>**spring-boot**</dt><dd>Spring-boot Server application.</dd><dl>|spring-boot|

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4707,7 +4707,7 @@ public CodegenParameter fromRequestBody(RequestBody body, Set<String> imports, S
47074707
codegenParameter.items = codegenProperty.items;
47084708
codegenParameter.mostInnerItems = codegenProperty.mostInnerItems;
47094709
codegenParameter.dataType = getTypeDeclaration(arraySchema);
4710-
codegenParameter.baseType = getSchemaType(arraySchema);
4710+
codegenParameter.baseType = getSchemaType(inner);
47114711
codegenParameter.isContainer = Boolean.TRUE;
47124712
codegenParameter.isListContainer = Boolean.TRUE;
47134713

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

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen
6060
public static final String SWAGGER_ANNOTATIONS = "swaggerAnnotations";
6161
public static final String SERVICE_INTERFACE = "serviceInterface";
6262
public static final String SERVICE_IMPLEMENTATION = "serviceImplementation";
63+
public static final String REACTIVE = "reactive";
64+
6365

6466
private String basePackage;
6567
private String invokerPackage;
@@ -72,6 +74,7 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen
7274
private boolean swaggerAnnotations = false;
7375
private boolean serviceInterface = false;
7476
private boolean serviceImplementation = false;
77+
private boolean reactive = false;
7578

7679
public KotlinSpringServerCodegen() {
7780
super();
@@ -140,7 +143,7 @@ public KotlinSpringServerCodegen() {
140143
addOption(SERVER_PORT, "configuration the port in which the sever is to run on", serverPort);
141144
addOption(CodegenConstants.MODEL_PACKAGE, "model package for generated code", modelPackage);
142145
addOption(CodegenConstants.API_PACKAGE, "api package for generated code", apiPackage);
143-
addSwitch(EXCEPTION_HANDLER, "generate default global exception handlers", exceptionHandler);
146+
addSwitch(EXCEPTION_HANDLER, "generate default global exception handlers (not compatible with reactive. enabling reactive will disable exceptionHandler )", exceptionHandler);
144147
addSwitch(GRADLE_BUILD_FILE, "generate a gradle build file using the Kotlin DSL", gradleBuildFile);
145148
addSwitch(SWAGGER_ANNOTATIONS, "generate swagger annotations to go alongside controllers and models", swaggerAnnotations);
146149
addSwitch(SERVICE_INTERFACE, "generate service interfaces to go alongside controllers. In most " +
@@ -149,7 +152,7 @@ public KotlinSpringServerCodegen() {
149152
addSwitch(SERVICE_IMPLEMENTATION, "generate stub service implementations that extends service " +
150153
"interfaces. If this is set to true service interfaces will also be generated", serviceImplementation);
151154
addSwitch(USE_BEANVALIDATION, "Use BeanValidation API annotations to validate data types", useBeanValidation);
152-
155+
addSwitch(REACTIVE, "use coroutines for reactive behavior", reactive);
153156
supportedLibraries.put(SPRING_BOOT, "Spring-boot Server application.");
154157
setLibrary(SPRING_BOOT);
155158

@@ -240,6 +243,14 @@ public void setUseBeanValidation(boolean useBeanValidation) {
240243
this.useBeanValidation = useBeanValidation;
241244
}
242245

246+
public boolean isReactive() {
247+
return reactive;
248+
}
249+
250+
public void setReactive(boolean reactive) {
251+
this.reactive = reactive;
252+
}
253+
243254
@Override
244255
public CodegenType getTag() {
245256
return CodegenType.SERVER;
@@ -332,6 +343,14 @@ public void processOpts() {
332343
}
333344
writePropertyBack(USE_BEANVALIDATION, useBeanValidation);
334345

346+
if (additionalProperties.containsKey(REACTIVE) && library.equals(SPRING_BOOT)) {
347+
this.setReactive(convertPropertyToBoolean(REACTIVE));
348+
// spring webflux doesn't support @ControllerAdvice
349+
this.setExceptionHandler(false);
350+
}
351+
writePropertyBack(REACTIVE, reactive);
352+
writePropertyBack(EXCEPTION_HANDLER, exceptionHandler);
353+
335354
modelTemplateFiles.put("model.mustache", ".kt");
336355
apiTemplateFiles.put("api.mustache", ".kt");
337356
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));

modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,15 @@ import io.swagger.annotations.AuthorizationScope
1414
import org.springframework.http.HttpStatus
1515
import org.springframework.http.MediaType
1616
import org.springframework.http.ResponseEntity
17-
import org.springframework.stereotype.Controller
17+
1818
import org.springframework.web.bind.annotation.RequestBody
1919
import org.springframework.web.bind.annotation.RequestPart
2020
import org.springframework.web.bind.annotation.RequestParam
2121
import org.springframework.web.bind.annotation.PathVariable
2222
import org.springframework.web.bind.annotation.RequestHeader
2323
import org.springframework.web.bind.annotation.RequestMethod
2424
import org.springframework.web.bind.annotation.RequestMapping
25+
import org.springframework.web.bind.annotation.RestController
2526
{{#useBeanValidation}}
2627
import org.springframework.validation.annotation.Validated
2728
{{/useBeanValidation}}
@@ -39,10 +40,13 @@ import javax.validation.constraints.Pattern
3940
import javax.validation.constraints.Size
4041
{{/useBeanValidation}}
4142

43+
{{#reactive}}
44+
import kotlinx.coroutines.flow.Flow;
45+
{{/reactive}}
4246
import kotlin.collections.List
4347
import kotlin.collections.Map
4448

45-
@Controller
49+
@RestController
4650
{{#useBeanValidation}}
4751
@Validated
4852
{{/useBeanValidation}}
@@ -68,12 +72,12 @@ class {{classname}}Controller({{#serviceInterface}}@Autowired(required = true) v
6872
value = [{{#responses}}ApiResponse(code = {{{code}}}, message = "{{{message}}}"{{#baseType}}, response = {{{baseType}}}::class{{/baseType}}{{#containerType}}, responseContainer = "{{{containerType}}}"{{/containerType}}){{#hasMore}},{{/hasMore}}{{/responses}}]){{/swaggerAnnotations}}
6973
@RequestMapping(
7074
value = ["{{#lambda.escapeDoubleQuote}}{{path}}{{/lambda.escapeDoubleQuote}}"],{{#singleContentTypes}}{{#hasProduces}}
71-
produces = "{{{vendorExtensions.x-accepts}}}", {{/hasProduces}}{{#hasConsumes}}
75+
produces = "{{{vendorExtensions.x-accepts}}}",{{/hasProduces}}{{#hasConsumes}}
7276
consumes = "{{{vendorExtensions.x-contentType}}}",{{/hasConsumes}}{{/singleContentTypes}}{{^singleContentTypes}}{{#hasProduces}}
7377
produces = [{{#produces}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/produces}}], {{/hasProduces}}{{#hasConsumes}}
7478
consumes = [{{#consumes}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/consumes}}],{{/hasConsumes}}{{/singleContentTypes}}
7579
method = [RequestMethod.{{httpMethod}}])
76-
fun {{operationId}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{#hasMore}},{{/hasMore}}{{/allParams}}): ResponseEntity<{{>returnTypes}}> {
80+
{{#reactive}}{{^isListContainer}}suspend {{/isListContainer}}{{/reactive}}fun {{operationId}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{#hasMore}},{{/hasMore}}{{/allParams}}): ResponseEntity<{{>returnTypes}}> {
7781
return {{>returnValue}}
7882
}
7983
{{/operation}}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{{#isBodyParam}}{{#swaggerAnnotations}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}} {{^isContainer}}{{#allowableValues}}, allowableValues="{{{allowableValues}}}"{{/allowableValues}}{{/isContainer}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}){{/swaggerAnnotations}} {{#useBeanValidation}}@Valid{{/useBeanValidation}} @RequestBody {{paramName}}: {{^reactive}}{{>optionalDataType}}{{/reactive}}{{#reactive}}{{^isListContainer}}Mono{{/isListContainer}}{{#isListContainer}}Flux{{/isListContainer}}<{{{baseType}}}>{{/reactive}}{{/isBodyParam}}
1+
{{#isBodyParam}}{{#swaggerAnnotations}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}} {{^isContainer}}{{#allowableValues}}, allowableValues="{{{allowableValues}}}"{{/allowableValues}}{{/isContainer}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}){{/swaggerAnnotations}} {{#useBeanValidation}}@Valid{{/useBeanValidation}} @RequestBody {{paramName}}: {{^reactive}}{{>optionalDataType}}{{/reactive}}{{#reactive}}{{^isListContainer}}{{>optionalDataType}}{{/isListContainer}}{{#isListContainer}}Flow<{{{baseType}}}>{{/isListContainer}}{{/reactive}}{{/isBodyParam}}

modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradleKts.mustache

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ buildscript {
66
mavenCentral()
77
}
88
dependencies {
9-
classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.3.RELEASE")
9+
classpath("org.springframework.boot:spring-boot-gradle-plugin:2.2.0.M3")
1010
}
1111
}
1212

@@ -23,18 +23,26 @@ tasks.withType<KotlinCompile> {
2323
}
2424

2525
plugins {
26-
val kotlinVersion = "1.2.60"
26+
val kotlinVersion = "1.3.30"
2727
id("org.jetbrains.kotlin.jvm") version kotlinVersion
2828
id("org.jetbrains.kotlin.plugin.jpa") version kotlinVersion
2929
id("org.jetbrains.kotlin.plugin.spring") version kotlinVersion
30-
id("org.springframework.boot") version "2.0.3.RELEASE"
30+
id("org.springframework.boot") version "2.2.0.M3"
3131
id("io.spring.dependency-management") version "1.0.5.RELEASE"
3232
}
3333

3434
dependencies {
35+
val kotlinxCoroutinesVersion="1.2.0"
3536
compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
3637
compile("org.jetbrains.kotlin:kotlin-reflect")
38+
{{^reactive}}
3739
compile("org.springframework.boot:spring-boot-starter-web")
40+
{{/reactive}}
41+
{{#reactive}}
42+
compile("org.springframework.boot:spring-boot-starter-webflux")
43+
compile("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinxCoroutinesVersion")
44+
compile("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:$kotlinxCoroutinesVersion")
45+
{{/reactive}}
3846
{{#swaggerAnnotations}}
3947
compile("io.swagger:swagger-annotations:1.5.21")
4048
{{/swaggerAnnotations}}
@@ -47,3 +55,9 @@ dependencies {
4755
exclude(module = "junit")
4856
}
4957
}
58+
59+
repositories {
60+
mavenCentral()
61+
maven { url = uri("https://repo.spring.io/snapshot") }
62+
maven { url = uri("https://repo.spring.io/milestone") }
63+
}

modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/pom.mustache

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@
66
<name>{{artifactId}}</name>
77
<version>{{artifactVersion}}</version>
88
<properties>
9-
<kotlin.version>1.2.60</kotlin.version>
9+
<kotlin.version>1.3.30</kotlin.version>
10+
<kotlinx-coroutines.version>1.2.0</kotlinx-coroutines.version>
1011
</properties>
1112
<parent>
1213
<groupId>org.springframework.boot</groupId>
1314
<artifactId>spring-boot-starter-parent</artifactId>
14-
<version>2.0.3.RELEASE</version>
15+
<version>2.2.0.M3</version>
1516
</parent>
1617
<build>
1718
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
@@ -77,8 +78,26 @@
7778
</dependency>
7879
<dependency>
7980
<groupId>org.springframework.boot</groupId>
81+
{{^reactive}}
8082
<artifactId>spring-boot-starter-web</artifactId>
83+
{{/reactive}}
84+
{{#reactive}}
85+
<artifactId>spring-boot-starter-webflux</artifactId>
86+
{{/reactive}}
8187
</dependency>
88+
{{#reactive}}
89+
<dependency>
90+
<groupId>org.jetbrains.kotlinx</groupId>
91+
<artifactId>kotlinx-coroutines-core</artifactId>
92+
<version>${kotlinx-coroutines.version}</version>
93+
</dependency>
94+
<dependency>
95+
<groupId>org.jetbrains.kotlinx</groupId>
96+
<artifactId>kotlinx-coroutines-reactor</artifactId>
97+
<version>${kotlinx-coroutines.version}</version>
98+
</dependency>
99+
{{/reactive}}
100+
82101
{{#swaggerAnnotations}}
83102
<dependency>
84103
<groupId>io.swagger</groupId>
@@ -116,4 +135,34 @@
116135
<scope>test</scope>
117136
</dependency>
118137
</dependencies>
138+
<repositories>
139+
<repository>
140+
<id>spring-snapshots</id>
141+
<name>Spring Snapshots</name>
142+
<url>https://repo.spring.io/snapshot</url>
143+
<snapshots>
144+
<enabled>true</enabled>
145+
</snapshots>
146+
</repository>
147+
<repository>
148+
<id>spring-milestones</id>
149+
<name>Spring Milestones</name>
150+
<url>https://repo.spring.io/milestone</url>
151+
</repository>
152+
</repositories>
153+
<pluginRepositories>
154+
<pluginRepository>
155+
<id>spring-snapshots</id>
156+
<name>Spring Snapshots</name>
157+
<url>https://repo.spring.io/snapshot</url>
158+
<snapshots>
159+
<enabled>true</enabled>
160+
</snapshots>
161+
</pluginRepository>
162+
<pluginRepository>
163+
<id>spring-milestones</id>
164+
<name>Spring Milestones</name>
165+
<url>https://repo.spring.io/milestone</url>
166+
</pluginRepository>
167+
</pluginRepositories>
119168
</project>
Original file line numberDiff line numberDiff line change
@@ -1 +1,15 @@
1+
pluginManagement {
2+
repositories {
3+
maven { url = uri("https://repo.spring.io/snapshot") }
4+
maven { url = uri("https://repo.spring.io/milestone") }
5+
gradlePluginPortal()
6+
}
7+
resolutionStrategy {
8+
eachPlugin {
9+
if (requested.id.id == "org.springframework.boot") {
10+
useModule("org.springframework.boot:spring-boot-gradle-plugin:${requested.version}")
11+
}
12+
}
13+
}
14+
}
115
rootProject.name = "{{artifactId}}"
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{{#isMapContainer}}{{#reactive}}Mono<{{/reactive}}Map<String, {{{returnType}}}{{#reactive}}>{{/reactive}}>{{/isMapContainer}}{{#isListContainer}}{{#reactive}}Flux{{/reactive}}{{^reactive}}List{{/reactive}}<{{{returnType}}}>{{/isListContainer}}{{^returnContainer}}{{#reactive}}Mono<{{{returnType}}}>{{/reactive}}{{^reactive}}{{{returnType}}}{{/reactive}}{{/returnContainer}}
1+
{{#isMapContainer}}Map<String, {{{returnType}}}>{{/isMapContainer}}{{#isListContainer}}{{#reactive}}Flow{{/reactive}}{{^reactive}}List{{/reactive}}<{{{returnType}}}>{{/isListContainer}}{{^returnContainer}}{{{returnType}}}{{/returnContainer}}

modules/openapi-generator/src/main/resources/kotlin-spring/service.mustache

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ package {{package}}
22

33
{{#imports}}import {{import}}
44
{{/imports}}
5-
5+
{{#reactive}}
6+
import kotlinx.coroutines.flow.Flow;
7+
{{/reactive}}
68
{{#operations}}
79
interface {{classname}}Service {
810
{{#operation}}
911

10-
fun {{operationId}}({{#allParams}}{{paramName}}: {{>optionalDataType}}{{#hasMore}}, {{/hasMore}}{{/allParams}}): {{>returnTypes}}
12+
{{#reactive}}{{^isListContainer}}suspend {{/isListContainer}}{{/reactive}}fun {{operationId}}({{#allParams}}{{paramName}}: {{^isBodyParam}}{{>optionalDataType}}{{/isBodyParam}}{{#isBodyParam}}{{^reactive}}{{>optionalDataType}}{{/reactive}}{{#reactive}}{{^isListContainer}}{{>optionalDataType}}{{/isListContainer}}{{#isListContainer}}Flow<{{{baseType}}}>{{/isListContainer}}{{/reactive}}{{/isBodyParam}}{{#hasMore}}, {{/hasMore}}{{/allParams}}): {{>returnTypes}}
1113
{{/operation}}
1214
}
1315
{{/operations}}

0 commit comments

Comments
 (0)