Reputation: 835
I must be missing something obvious will be my epitaph. I've create a swagger 2.0 doc to represent a simple API. It has one POST operation that returns an Integer. I used the openapi-generator-maven-plugin plugin to generate controllers, models, etc in my Spring Boot project.
How do I create a controller to handle the request?
Looking in /work-queue-api/target/generated-sources/openapi/src/main/java
I see 3 things. ApiUtil.java
, WorkItemApi.java
(interface), WorkItemApiController.java
(implementation)
I created a new controller in my application that implements WorkItemApiController. But when I do that Spring complains that its methods are already mapped.
The API "works" in that I can start it and use the Swagger UI to POST. But obviously the request is not actually handled and a default response is returned. The generated interface is pasted below. It has one implemented method. I want to able to call a service in that method. Or a method that overrides it.
Here is the generated interface for WorkItemApi
/**
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech) (4.0.2).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
package com.etisoftware.work_queue.webapi.controller.v1;
import com.etisoftware.work_queue.webapi.model.v1.Error;
import com.etisoftware.work_queue.webapi.model.v1.NewWorkItem;
import com.etisoftware.work_queue.webapi.model.v1.WorkItemResponse;
import io.swagger.annotations.*;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.Valid;
import javax.validation.constraints.*;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@Validated
@Api(value = "WorkItem", description = "the WorkItem API")
public interface WorkItemApi {
default Optional<NativeWebRequest> getRequest() {
return Optional.empty();
}
@ApiOperation(value = "Adds a new workItem", nickname = "v1WorkItemsPost", notes = "", response = WorkItemResponse.class, tags={ "workItem", })
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK", response = WorkItemResponse.class),
@ApiResponse(code = 201, message = "Successful operation", response = WorkItemResponse.class),
@ApiResponse(code = 400, message = "Bad Request", response = Error.class),
@ApiResponse(code = 401, message = "Unauthorized"),
@ApiResponse(code = 403, message = "Forbidden", response = Error.class),
@ApiResponse(code = 404, message = "Not Found"),
@ApiResponse(code = 500, message = "Internal server error", response = Error.class) })
@RequestMapping(value = "/v1/work-items",
produces = { "application/problem+json", "application/json" },
consumes = { "application/json" },
method = RequestMethod.POST)
default ResponseEntity<WorkItemResponse> v1WorkItemsPost(@ApiParam(value = "Parameters to represent a new work item." ,required=true ) @Valid @RequestBody NewWorkItem newWorkItem) {
getRequest().ifPresent(request -> {
for (MediaType mediaType: MediaType.parseMediaTypes(request.getHeader("Accept"))) {
if (mediaType.isCompatibleWith(MediaType.valueOf("application/json"))) {
ApiUtil.setExampleResponse(request, "application/json", "{ \"controllerWorkNumber\" : 0.8008281904610115}");
break;
}
}
});
return new ResponseEntity<>(HttpStatus.valueOf(200));
}
}
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>4.0.2</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${project.basedir}/src/main/resources/swagger.yaml</inputSpec>
<generatorName>spring</generatorName>
<addCompileSourceRoot>true</addCompileSourceRoot>
<configOptions>
<basePackage>com.etisoftware.work_queue</basePackage>
<configPackage>
com.etisoftware.work_queue.webapi.configuration
</configPackage>
<apiPackage>
com.etisoftware.work_queue.webapi.controller.v1
</apiPackage>
<modelPackage>
com.etisoftware.work_queue.webapi.model.v1
</modelPackage>
<invokerPackage>
com.etisoftware.work_queue
</invokerPackage>
<swaggerDocketConfig>true</swaggerDocketConfig>
<useOptional>true</useOptional>
<returnSuccessCode>true</returnSuccessCode>
<useTags>true</useTags>
<virtualService>false</virtualService>
<dateLibrary>java8</dateLibrary>
<hideGenerationTimestamp>true</hideGenerationTimestamp>
</configOptions>
</configuration>
</execution>
</executions>
</plugin>
Upvotes: 1
Views: 13637
Reputation: 835
The solution is that I was using an older version of the plugin. Version 4.2.3 includes configuration options to exclude the generation of the controller, which is exactly what I need.
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>4.2.3</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${project.basedir}/src/main/resources/swagger.yaml</inputSpec>
<generatorName>spring</generatorName>
<addCompileSourceRoot>true</addCompileSourceRoot>
<configOptions>
<basePackage>com.etisoftware.work_queue</basePackage>
<configPackage>
com.etisoftware.work_queue.webapi.configuration
</configPackage>
<apiPackage>
com.etisoftware.work_queue.webapi.controller.v1
</apiPackage>
<modelPackage>
com.etisoftware.work_queue.webapi.model.v1
</modelPackage>
<invokerPackage>
com.etisoftware.work_queue
</invokerPackage>
<swaggerDocketConfig>true</swaggerDocketConfig>
<useOptional>true</useOptional>
<returnSuccessCode>true</returnSuccessCode>
<useTags>true</useTags>
<virtualService>false</virtualService>
<dateLibrary>java8</dateLibrary>
<hideGenerationTimestamp>true</hideGenerationTimestamp>
<interfaceOnly>true</interfaceOnly>
<skipDefaultInterface>true</skipDefaultInterface>
</configOptions>
</configuration>
</execution>
</executions>
</plugin>
One quick start tip I would offer is that on first generation, allow the plugin to generate the controller. You can then scrape out all the annotations from the interface and stuff into your own controller. Then clean the project, and regenerate sources without the controllers.
Upvotes: 2