Reputation: 305
We are using the openapi-generator-maven-plugin version 5.0.1 to generate our APIs. I am trying to specify a request that includes a DTO and also a file.
The first weird thing is that the generated code doesn't use the DTO, it basically flattens the fields, so that the API expects each of the fields to be specified. However, we're not really too concerned about this issue, because we can just specify each field (although it would be nice if it worked as expected).
The problem that is killing us is that the generated classes for the API and the API Delegate are not consistent with each other. The generated API treats each of the fields as a String
. However, the API Delegate treats them as Optional<String>
. So when we try to compile the code, the API gets a compile error because it's passing String to the Delegate, and the Delegate wants Optional<String>
.
Here is our POM, with the related dependencies and plugin config:
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.6.2</version>
</dependency>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>jackson-databind-nullable</artifactId>
<version>0.2.1</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
...
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>5.0.1</version>
<executions>
<execution>
<id>processor-Generate</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>
${project.basedir}/apis/innovation-ivp-inventory-accuracy-acl-api.yml
</inputSpec>
<generatorName>spring</generatorName>
<apiPackage>${project.groupId}.inventory.accuracy.acl.api</apiPackage>
<modelPackage>${project.groupId}.inventory.accuracy.acl.dto</modelPackage>
<invokerPackage>${project.groupId}.inventory.accuracy.acl.api.handler</invokerPackage>
<supportingFilesToGenerate>ApiUtil.java,OpenAPIDocumentationConfig.java
</supportingFilesToGenerate>
<configOptions>
<useTags>true</useTags>
<dateLibrary>java8-localdatetime</dateLibrary>
<java8>true</java8>
<delegatePattern>true</delegatePattern>
<useBeanValidation>true</useBeanValidation>
<useOptional>true</useOptional>
<configPackage>${project.groupId}.inventory.accuracy.acl.api</configPackage>
</configOptions>
<output>${project.build.directory}/generated-sources</output>
</configuration>
</execution>
</executions>
</plugin>
Here is our OpenAPI spec:
'/email':
post:
tags:
- email-service
summary: Email Service
operationId: sendEmail
requestBody:
required: true
content:
multipart/mixed:
schema:
allOf:
- $ref: '#/components/schemas/EmailRequestDTO'
- type: object
properties:
file:
type: string
format: binary
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/EmailResponseDTO'
components:
schemas:
EmailRequestDTO:
type: object
properties:
sendTo:
type: string
sentFrom:
type: string
subject:
type: string
content:
type: string
EmailResponseDTO:
type: object
properties:
status:
type: string
errorMessage:
type: string
Here is the OpenAPI-generated API class (note that the parameters are all String):
public interface EmailServiceApi {
@ApiOperation(value = "Email Service", nickname = "sendEmail", notes = "", response = EmailResponseDTO.class, tags={ "email-service", })
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK", response = EmailResponseDTO.class) })
@PostMapping(
value = "/email",
produces = { "application/json" },
consumes = { "multipart/mixed" }
)
default ResponseEntity<EmailResponseDTO> sendEmail(@ApiParam(value = "") @Valid @RequestPart(value = "sendTo", required = false) String sendTo,@ApiParam(value = "") @Valid @RequestPart(value = "sentFrom", required = false) String sentFrom,@ApiParam(value = "") @Valid @RequestPart(value = "subject", required = false) String subject,@ApiParam(value = "") @Valid @RequestPart(value = "content", required = false) String content,@ApiParam(value = "") @Valid @RequestPart(value = "file", required = false) MultipartFile file) {
return getDelegate().sendEmail(sendTo, sentFrom, subject, content, file);
}
}
Here is the OpenAPI-generated API Delegate class (note that the parameters are all Optional):
public interface EmailServiceApiDelegate {
default ResponseEntity<EmailResponseDTO> sendEmail(Optional<String> sendTo,
Optional<String> sentFrom,
Optional<String> subject,
Optional<String> content,
MultipartFile file) {
getRequest().ifPresent(request -> {
for (MediaType mediaType: MediaType.parseMediaTypes(request.getHeader("Accept"))) {
if (mediaType.isCompatibleWith(MediaType.valueOf("application/json"))) {
String exampleString = "{ \"errorMessage\" : \"errorMessage\", \"status\" : \"status\" }";
ApiUtil.setExampleResponse(request, "application/json", exampleString);
break;
}
}
});
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
}
Upvotes: 1
Views: 4400
Reputation: 124
Using allOf
combines all schema listed in one. The properties of EmailRequestDTO
and those of the inline defined object are generated as parameters and not as a DTO. See https://swagger.io/docs/specification/data-models/oneof-anyof-allof-not/#allof
If you don't want Optional String are generated as parameter in the delegate, remove useOptional
configuration. See https://openapi-generator.tech/docs/generators/spring/
Upvotes: 1