Swager CodGen generating code ApiController.java with multiple try catch - java

I am looking for generating code with multiple try catch in APIController.java which is generated by SwagerCodeGen.
swagger.yaml file
paths:
/system:
post:
tags:
- New
summary: System info
description: Initial System Info
operationId: createSystem
consumes:
- application/json
produces:
- application/json
parameters:
- in: body
name: systemDetails
description: Contains the JSON Object
required: true
schema:
$ref: '#/definitions/SystemDetails'
- name: AuthKey
in: query
description: Key for Authentication and Authorization.
required: true
type: string
format: uuid
responses:
'201':
description: System Created Successfully
schema:
$ref: '#/definitions/Response'
'400':
description: Request Failed
'401':
description: Unauthorized
'500':
description: Internal Server Error
Swager generated code as below,
SystemApi.java
#ApiOperation(value = "System", notes = "Initial System Info", response = Response.class, tags={ "System", })
#ApiResponses(value = {
#ApiResponse(code = 201, message = "System Created Successfully", response = Response.class),
#ApiResponse(code = 400, message = "Request Failed", response = Void.class),
#ApiResponse(code = 401, message = "Unauthorized", response = Void.class),
#ApiResponse(code = 404, message = "Not Found", response = Void.class),
#ApiResponse(code = 500, message = "Internal Server Error", response = Void.class) })
#RequestMapping(value = "/system",
produces = { "application/json" },
consumes = { "application/json" },
method = RequestMethod.POST)
ResponseEntity<Response> createSystem(#ApiParam(value = "Contains the JSON Object" ,required=true ) #Valid #RequestBody SystemDetails systemDetails, #NotNull#ApiParam(value = "Key for Authentication and Authorization.", required = true) #RequestParam(value = "AuthKey", required = true) UUID authKey);
SystemApiController.Java
public ResponseEntity<Response> createSystem(
#ApiParam(value = "Contains the JSON Object",
required = true) #Valid #RequestBody SystemDetails systemDetails,
#NotNull #ApiParam(
value = "Key for Authentication and Authorization.",
required = true) #RequestParam(value = "AuthKey", required = true) UUID authKey) {
// do some magic!
return delegate.createSystem(systemDetails, authKey);
}
Is there any way to add try catch auto generated from Swagger CodeGen like below?
public ResponseEntity<Response> createSystem(
#ApiParam(value = "Contains the JSON Object",
required = true) #Valid #RequestBody SystemDetails systemDetails,
#NotNull #ApiParam(
value = "Key for Authentication and Authorization.",
required = true) #RequestParam(value = "AuthKey", required = true) UUID authKey) {
// do some magic!
try{
return delegate.createSystem(systemDetails, authKey);
}catch(InvalidInputException e){
return new ResponseEntity(new Response(HTTPSTATUS.BAD_REQUEST));
}
}
Or please suggest alternate way. Now I am handling all exceptions in SystemService.java, not throwing any exception to Controller. Because of this I need to rollback all Transactions manually in service side.

Swagger codegen uses moustache templates to generate your code.
You can refer to https://github.com/swagger-api/swagger-codegen#modifying-the-client-library-format to customize the syntax of generated classes

Related

Spring Rest Controller with HttpServletRequest for upload resulting in no input file upload in Swagger

I have spring rest controller with some parameters and HttpServletRequest in input. I use it to stream input file. Simplifying:
#PostMapping(path = "...", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
#Operation(summary = "Create document", description = "upload file for creating a document")
#ApiResponse(content = #Content(mediaType = MediaType.TEXT_PLAIN_VALUE, schema = #Schema(implementation = MyDTO.class)))
#ApiResponses(value = { #ApiResponse(responseCode = "200", description = "Data found"),
#ApiResponse(responseCode = "400", description = "Request not compliant with the defined schema")
...
public ResponseEntity<MyDTO> myUpl(
#PathVariable("myParam1") Long param1,
#RequestParam(name = "myParam2", required = true) Integer myParam2,
HttpServletRequest request ) {
So when I invoke swagger-ui and produce swagger yaml there is no file input.
The code works perfectly.
I need to clarify in swagger the input file for frontend team.
How can I do that?
EDIT:
Following other posts, temporanely added to controller:
#RequestBody(description = "Input file",
content = #Content(mediaType = MediaType.MULTIPART_FORM_DATA_VALUE,
schema = #Schema(implementation = MultipartRequest.class),
encoding = #Encoding(name = "file", contentType = "application/pdf")))
At least I have in swagger yaml:
requestBody:
description: Input file
content:
multipart/form-data:
schema:
$ref: '#/components/schemas/MultipartRequest'
encoding:
file:
contentType: application/pdf
and un swagger-ui:
Request body multipart/form-data
Input file
fileMap
object
fileNames
object
multiFileMap
object
It's the right way? There's something better? Is it possible to show Input File button in swagger-ui?

How to return different objects for different response codes in Swagger-generated REST API?

I want to respond with different result objects in a Swagger generated API. The type of object is dependent on the result code.
But it seems that the Swagger codegen generates only code that allows the first defined/used type to be returned.
An example Swagger definition that returns different objects in the OK and error case is like:
swagger: "2.0"
info:
description: "API"
version: 1.0.0
title: Example
host: localhost:8080
schemes:
- http
paths:
/exampleCall:
get:
operationId: exampleCall
produces:
- application/json
responses:
200:
description: OK
schema:
$ref: '#/definitions/exampleResponse'
400:
description: Error
schema:
$ref: '#/definitions/exampleError'
definitions:
exampleResponse:
type: object
properties:
result:
type: string
exampleError:
type: object
properties:
code:
type: string
This then gets generated by the SwaggerCodeGen into following API interface
#Validated
#Api(value = "exampleCall", description = "the exampleCall API")
#RequestMapping(value = "")
public interface ExampleCallApi {
ExampleCallApiDelegate getDelegate();
#ApiOperation(value = "", nickname = "exampleCall", notes = "", response = ExampleResponse.class, tags={ })
#ApiResponses(value = {
#ApiResponse(code = 200, message = "OK", response = ExampleResponse.class),
#ApiResponse(code = 400, message = "Error", response = ExampleError.class) })
#RequestMapping(value = "/exampleCall",
produces = { "application/json" },
method = RequestMethod.GET)
default ResponseEntity<ExampleResponse> exampleCall() {
return getDelegate().exampleCall();
}
}
But when I try to implement the delegate like this
public class ExampleCallApiDelegateImpl implements ExampleCallApiDelegate {
#Override
public ResponseEntity<ExampleResponse> exampleCall() {
ExampleError error = new ExampleError();
error.setCode("123");
return new ResponseEntity<ExampleError>(error, HttpStatus.BAD_REQUEST);
}
}
it of course fails to compile because of incorrect return types.
What would be the proper way to implement different return objects per response code with that Swagger generated API?
Is there even a proper way?

File Upload on Swagger Controller Interface

I'm creating an API micro-service that provides file storage with AWS. I'm putting together the Swagger and Controller, and we need to be able to allow users to upload a file on the Swagger. The problem is our controller is set up as an interface instead of a class, and solutions from Google/SO aren't making the cut to be able to work with interfaces. To clarify, I don't need to manipulate the file at all, just take it in. Our internal implementation methods will take then send it off to S3.
This is using Java 11, AWS S3, Spring Boot, and Swagger 2. I've tried using #ApiParam and #FormDataParam inside the method createFile, but I've gotten two different errors:
method must be abstract
annotations are not allowed here.
#RequestMapping(value = {"v3/registration/documents", "v4/registration/documents"})
#RestController
#Api(
value = "file-storage",
description = "File storage service",
tags = {"file-storage"})
public interface FileController {
#PostMapping(
value = "/{salesPlanAff}",
produces = {MediaType.APPLICATION_JSON_VALUE},
consumes = {MediaType.APPLICATION_JSON_VALUE})
#ApiOperation(value = "Upload a file")
#ApiResponses(
value = {
#ApiResponse(code = 200, message = "Success", response = FileResponseDTO.class),
#ApiResponse(code = 201, message = "Created"),
#ApiResponse(code = 400, message = "Bad Request"),
#ApiResponse(code = 401, message = "Unauthorized"),
#ApiResponse(code = 403, message = "Forbidden"),
#ApiResponse(code = 404, message = "Not Found"),
#ApiResponse(code = 500, message = "Internal Server Error")
})
void createFile(
#PathVariable(required = true, name = "webSessionId") String webSessionId,
#PathVariable(required = false, name = "salesPlanAff") String salesPlanAff);
What I expected is to have a button on my swagger page allowing file upload, didn't quite expect this much difficulty in adding file upload.
I have a FileUpload in my swagger page and it works like a charm. The only difference from your is that I am not doing it on an interface...
import org.springframework.web.multipart.MultipartFile;
...
#ApiOperation(value = "Analyse the identifiers in the file")
#RequestMapping(value = "/form", method = RequestMethod.POST, produces = "application/json")
#ResponseBody
public AnalysisResult getPostFile( #ApiParam(name = "file", value = "The file")
#RequestPart MultipartFile file,
HttpServletRequest r) {
UserData ud = controller.getUserData(file);
return controller.analyse(ud, r, file.getOriginalFilename());
}
I trimmed off a little bit this code, but you can find a the original one in our repository
Also, working version of this code can be executed tested here
Thanks
I figured out how to get the annotations in, part of it stemmed from typos. For anyone interested, here's the solution:
public interface FileController {
#PostMapping(
value = "/{salesPlanAff}",
produces = {MediaType.APPLICATION_JSON_VALUE},
consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
#ApiOperation(value = "Upload a file")
#ApiResponses(
value = {
#ApiResponse(code = 200, message = "Success", response = FileResponseDTO.class),
#ApiResponse(code = 201, message = "Created"),
#ApiResponse(code = 400, message = "Bad Request"),
#ApiResponse(code = 401, message = "Unauthorized"),
#ApiResponse(code = 403, message = "Forbidden"),
#ApiResponse(code = 404, message = "Not Found"),
#ApiResponse(code = 500, message = "Internal Server Error")
})
void createFile(
#PathVariable(required = true, name = "webSessionId") String webSessionId,
#PathVariable(required = false, name = "salesPlanAff") String salesPlanAff,
#ApiParam(required = true, value = "Document to be uploaded")
#RequestPart MultipartFile multipartFile,
#ApiParam(required = true, value = "File Type")
#QueryParam("documentType") String documentType);

Can not upload file when using a swagger generated spring server

I want to implement a file readout function on my REST Service. Since I do not know how to use spring myself, I use swagger to generate the server code for me. Normally this works perfectly fine, but when I try to upload files I get the following error:
{
"timestamp": "2018-11-07T12:27:43.119Z",
"status": 400,
"error": "Bad Request",
"exception": "org.springframework.web.multipart.support.MissingServletRequestPartException",
"message": "Required request part 'file' is not present",
"path": "/requirements/import"
}
My yaml uses the following lines for the import function:
/requirements/import:
post:
consumes:
- multipart/form-data
description:
Returns all requirements contained in the submitted reqIf file.
parameters:
- name: reqIfFile
in: formData
type: file
description: The reqIf file that contains the requirements.
responses:
200:
description: An array of requirements.
schema:
type: array
items:
$ref: 'requirement'
The generated interface (with some added exceptions):
#javax.annotation.Generated(value = "io.swagger.codegen.languages.SpringCodegen", date = "2018-04-05T07:19:00.887Z")
#Api(value = "requirements", description = "the requirements API")
public interface RequirementsApi {
#ApiOperation(value = "", nickname = "requirementsImportPost", notes = "Returns all requirements contained in the submitted reqIf file.", response = Requirement.class, responseContainer = "List", tags = {})
#ApiResponses(value = {
#ApiResponse(code = 200, message = "An array of requirements.", response = Requirement.class, responseContainer = "List") })
#CrossOrigin(origins = "*")
#RequestMapping(value = "/requirements/import", produces = { "application/json" }, consumes = {
"multipart/form-data" }, method = RequestMethod.POST)
ResponseEntity<List<Requirement>> requirementsImportPost(
#ApiParam(value = "file detail") #Valid #RequestPart("file") MultipartFile reqIfFile)
throws IOException, ContinuumException;
}
The code that actually does the readout:
#javax.annotation.Generated(value = "io.swagger.codegen.languages.SpringCodegen", date = "2018-04-05T07:19:00.887Z")
#Controller
public class RequirementsApiController implements RequirementsApi {
#Override
public ResponseEntity<List<Requirement>> requirementsImportPost(
#ApiParam(value = "file detail") #Valid #RequestPart("file") final MultipartFile reqIfFile)
throws IOException, ContinuumException {
InputStream fileStream = new BufferedInputStream(reqIfFile.getInputStream());
List<Requirement> list = ReadReqIF.readReqIfFile(fileStream);
return new ResponseEntity<List<Requirement>>(list, HttpStatus.OK);
}
}
Can someone tell me where a possible error is?
I encountered the same problem with my swagger generated spring server.
I was able to workaround the problem by modifying the generated server code to change the name "file" in #RequestPart("file") to the name specified in the swagger spec. In your case, it should be #RequestPart("reqIfFile"). It'd have to be modified in both the interface and controller code.
There is likely a bug in the Spring server generator code in Swagger editor. I can't think of any other reason for the RequestPart annotation to be named "file" which is essentially the "type" and not name of the parameter.

Mass Assignment: Insecure Binder Configuration : How to use Spring Framework's #initBinder with Jersey framework

I want to avoid Mass Assignment: Insecure Binder Configuration issue for our application which is written in Jersey framework. I was thinking is there any other way we can use #InitBinder from spring and for each request to this service only allow to set the allowed properties and set all other properties to null.
#Controller
#Path("/ar")
#Api(tags = { "Request" })
public class RequestService extends AbstractService {
static final Logger logger = Logger
.getLogger("RequestServiceLogger");
#InitBinder
public void customizeBinding (WebDataBinder binder) {
System.out.println("Inside init binder ============== ");
//I want to allow the allowed field only for AccountRequest object
binder.setAllowedFields(allowedFields);
}
#Path("/submitrequest")
#POST
#Consumes({ "application/json" })
#Produces({ "application/json" })
#ApiOperation(value = "Validates a request", notes = "Validates a request", response = RequestResponse.class)
#ApiImplicitParams({ #io.swagger.annotations.ApiImplicitParam(name = "Auth", value = "value", required = true, dataType = "string", paramType = "header") })
#ApiResponses({
#io.swagger.annotations.ApiResponse(code = 200, message = "OK", responseHeaders = { #io.swagger.annotations.ResponseHeader(name = "X-ResponseTime", description = "Total Time Taken", response = String.class) }, response = RequestResponse.class),
#io.swagger.annotations.ApiResponse(code = 400, message = "Bad Request", response = com.model.ErrorDetail.class),
#io.swagger.annotations.ApiResponse(code = 401, message = "Unauthorized", response = com.model.ErrorDetail.class),
#io.swagger.annotations.ApiResponse(code = 403, message = "Forbidden", response = com.model.ErrorDetail.class),
#io.swagger.annotations.ApiResponse(code = 404, message = "Not Found", response = com.model.ErrorDetail.class),
#io.swagger.annotations.ApiResponse(code = 405, message = "Method Not Allowed", response = com.model.ErrorDetail.class),
#io.swagger.annotations.ApiResponse(code = 415, message = "Unsupported Media Type", response = com.model.ErrorDetail.class),
#io.swagger.annotations.ApiResponse(code = 500, message = "Internal Server error", response = com.ErrorDetail.class) })
public Response submitRequest(#ApiParam(value = "AccountRequest JSON input data.", required = true) AccountRequest accountRequest,
#Context HttpServletRequest request) throws Exception {
System.out.println("Inside submitRequest ============== ");
}
}
*** If there are any other alternative ways to filter request object properties please let me know.

Categories