I'm trying to document an API method that will receive a file and two parameters as int. Using swagger editor I was able to describe what I want, but couldn't replicate that using annotations.
This is what I draw on swagger editor
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
flow:
type: integer
environment:
type: integer
file:
type: string
format: binary
required: true
If I use consumes = MediaType.MULTIPART_FORM_DATA I get the params. And if I use consumes = MediaType.APPLICATION_OCTET_STREAM I get the file to upload.
#Operation(summary = "Unpack Files",
description = "Receives a packed zip or gzip file with xml files inside or receives xml files",
security = #SecurityRequirement(name = "apiKey"),
responses = {
#ApiResponse(responseCode = "201", description = "Created"),
#ApiResponse(responseCode = "400", description = "Something Went Wrong"),
#ApiResponse(responseCode = "401", description = "Unauthorized"),
#ApiResponse(responseCode = "503", description = "Service Unavailable")
},
requestBody = #RequestBody(
content = #Content(
mediaType = MediaType.MULTIPART_FORM_DATA,
schema = #Schema(implementation = Document.class, format = "binary"),
encoding = #Encoding(
name = "file",
contentType = "application/xml, application/zip, application/gzip"
)
),
required = true
)
)
#Post(value = "/unpack", consumes = MediaType.APPLICATION_OCTET_STREAM)
public Single<HttpResponse<String>> upload(StreamingFileUpload file, int flow, int environment) throws IOException {
return Single.just(new Document(file.getFilename(), environment, flow))
.flatMap(DocumentValidation::validateDocumentExtension)
.doOnError(throwable -> {
log.error("Validation exception: {}", throwable.getMessage());
exception = throwable.getMessage();
})
.doOnSuccess(doc -> {
log.info("File saved successfuly");
File tempFile = File.createTempFile(file.getFilename(), "temp");
file.transferTo(tempFile);
})
.map(success -> {
if (exception != null || !exception.equals("")) {
return HttpResponse.<String>status(HttpStatus.CREATED).body("Uploaded");
} else {
return HttpResponse.<String>status(HttpStatus.SERVICE_UNAVAILABLE).body(exception);
}
}
);
}
Thanks in advance.
Looks like missing #QueryValue
From documentation 6.4 Simple Request Binding:
Bindings from a request URI variable or request parameter | #QueryValue String myParam
From documentation 6.19 File Uploads:
The method is set to consume MULTIPART_FORM_DATA
The method parameters match form attribute names. In this case the file will match for example an
The StreamingFileUpload.transferTo(java.lang.String) method is used to transfer the file to the server.
Kotlin simple:
#Controller
class SomeController {
#Post(value = "/", consumes = [MediaType.MULTIPART_FORM_DATA])
fun upload(file: StreamingFileUpload,
#QueryValue flow: Int,
#QueryValue environment: Int): Single<HttpResponse<String>> {
val tempFile = File.createTempFile(file.filename, "temp")
return Single.fromPublisher(file.transferTo(tempFile))
.map { success ->
if (success) {
HttpResponse.ok("Uploaded");
} else {
HttpResponse.status<String>(HttpStatus.CONFLICT)
.body("Upload Failed")
}
}
}
}
Related
I currently have the problem that I am looking for an artifact in Jenkins. If this artifact can not be found, then a 404 should come back. So far this works quite well. Unfortunately I get no message and only the ErrorCode 404 back. I would like to return a message with more information.
Here's my code.
Endpoint:
#GET
#Path(API_RESOURCE_IMAGE_REPORT)
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.TEXT_HTML)
#Operation(summary = "", description = "")
#APIResponses(
value = {
#APIResponse(
responseCode = "200",
description =
"Request successful",
content = #Content(mediaType = MediaType.TEXT_HTML)),
#APIResponse(
responseCode = "404",
description = "Resource not found ",
content =
#Content(
mediaType = MediaType.APPLICATION_JSON,
schema = #Schema(implementation = NotFoundException.class))),
})
public Response getReport(#Parameter(
description = "",
required = true)
#PathParam("imageName") final String imageName,
#Parameter(description = "", required = true)
#PathParam("tag") final String tag,
#Parameter(description = "")
#PathParam("type") String type
) {
InputStream report = jenkinsClient.getReport(imageName, tag, type);
return Response.status(HttpURLConnection.HTTP_ACCEPTED).entity(report).build();
}
Jenkinsclient:
public InputStream getReport(final String imageName, final String tag, final String type) throws NotFoundException {
try {
final int lastSuccessfulBuildnumber = jenkinsClient.api().jobsApi().jobInfo(imageName, tag).lastSuccessfulBuild().number();
LOG.info("Last successful buildnumber: " + lastSuccessfulBuildnumber);
final InputStream report = jenkinsClient.api().jobsApi().artifact(imageName, tag, lastSuccessfulBuildnumber, Objects.equals(type, "image") ? "trivy_image_report.html" : "trivy_Dockerfile_report.html");
if (report == null) {
throw new NotFoundException("No dockerfile or image report found");
}
return report;
} catch (Exception e) {
throw new NotFoundException("No dockerfile or image scan report found");
}
}
I expected a 404 with a the message "No dockerfile or image scan report found". But i got only 404 without a message when i dont find an artefact. I used the "javax.ws.rs.NotFoundException" for NotFoundException.
Thanks for help
Thanks to Nikos Paraskevopoulos in the comments.
Ive added the response status in the Exception like this:
throw new NotFoundException(Response.status(HttpURLConnection.HTTP_NOT_FOUND).entity("your message").build());
this worked fine and i have the message in the response body
I am currently trying to return an input stream via my API. The input stream contains an html file that I previously fetch from Jenkins via the Cdancy Jenkinsclient via the input stream. I want to pass this html through my endpoint. If I enter Json as #Produce, then the HTML content comes with the note that the JSON can not be parsed. If I specify another MediyType, then a 406 comes back. Is it even bestpractise to return an inputstream or should I transform it into an outputstream first?
This is my Code:
Endpoint
#GET
#Path(API_RESOURCE_IMAGE_REPORT)
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_OCTET_STREAM)
#Operation(summary = "", description = "")
#APIResponses(
value = {
#APIResponse(
responseCode = "200",
description =
"",
content = #Content(mediaType = MediaType.APPLICATION_JSON)),
#APIResponse(
responseCode = "400",
description = "",
content =
#Content(
mediaType = MediaType.APPLICATION_JSON,
schema = #Schema(implementation = ErrorResponseDO.class))),
})
public Response getReport(#Parameter(
description = "",
required = true)
#PathParam("imageName") final String imageName,
#Parameter(description = "", required = true)
#PathParam("tag") final String tag,
#Parameter(description = "")
#PathParam("type") String type
) throws ApplicationException, IOException {
InputStream report = jenkinsClient.getReport(imageName, tag, type);
return Response.status(HttpURLConnection.HTTP_ACCEPTED).entity(report).build();
}
Jenkinsclient:
public InputStream getReport(final String imageName, final String tag, final String type) throws ApplicationException {
try {
final int lastSuccessfulBuildnumber = jenkinsClient.api().jobsApi().jobInfo(imageName, tag).lastSuccessfulBuild().number();
LOG.info("Last successful buildnumber: " + lastSuccessfulBuildnumber);
final InputStream report = jenkinsClient.api().jobsApi().artifact(imageName, tag, lastSuccessfulBuildnumber, Objects.equals(type, "image") ? "trivy_image_report.html" : "trivy_Dockerfile_report.html");
if (report == null) {
throw new NotFoundException();
}
return report;
} catch (Exception e) {
throw new NotFoundException();
}
}
Output:
Output is 406 everytime (TEXT_HTML, OCTET_STREAM, TEXT_PLAINE).
Only with #Produces(MediaType.APPLICATION_JSON) it is successfull with the html code bud with the message: json cant be parsed.
Thanks for your help
Like VGR stated. Problem was the caller which was not using text/html. Ive tested in swaggerui and set it to "text/html". Works as expected. Was application/json beforen and the reason for working only with application json as produce annoation.
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?
I try to send an image with some attributes from flutter to spring boot endpoint, but spring boot not received the image at all and it gives me this error:
Resolved [org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'image' is not present]
here is my code:
Spring boot
#PostMapping("")
public ResponseEntity<UsersEntity> createNewUser(#RequestParam(value = "image") MultipartFile image, UsersEntity user) {
UsersEntity response = userService.createUser(user, image);
return ResponseEntity.ok(response);
}
Flutter
var postUri = Uri.parse("http://localhost:8080/v1");
var request = new http.MultipartRequest("POST", postUri);
request.fields['fName'] = firstNameController.text;
request.fields['lName'] = lastNameController.text;
if(image != null) {
request.files.add(http.MultipartFile.fromBytes(
'image', image!, contentType: MediaType.parse('multipart/form-data')));
}
Map<String, String> headers = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Credentials": "true",
"Access-Control-Allow-Headers": "Origin,Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,locale",
"content-type": "application/json"};
request.headers.addAll(headers);
request.send().then((response) {
if (response.statusCode == 200) {
print("Success!");
} else {
print('Error!');
}
});
My service work very well with Postman, any idea how can I solve this issue?
Solution
Credit to this https://github.com/flutter/flutter/issues/37311#issuecomment-516967285
I just add filename and every thing work fine:
request.files.add(http.MultipartFile.fromBytes(
'image', image!,
contentType: MediaType.parse('multipart/form-data'),
filename: 'test.jpg'));
var uri = Uri.parse('$baseUrl/services/selfemployment/check-confirmation-code');
var request = new http.MultipartRequest("POST", uri);
request.headers.addAll(baseHeader);
request.fields['example'] = example;
request.fields['image'] = image;
http.Response response = await http.Response.fromStream(await request.send());
print('Uploaded! ${response.body} ++ ${response.statusCode}');
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