Swagger documentation: description of the content of the response - java

I have a simple fileUpload rest API which stores the uploaded file in database and returns with the unuque reference of the uploaded file in the database (uuid).
I use swagger to generate API documentation and it works like a charm but I can not find a way to add description text to describe the content of the response.
This is the signature of my REST:
#POST
#Path("/upload")
#Consumes(ExtendedMediaType.MULTIPART_FORM_DATA)
#ApiOperation(
value = "Save an image",
notes = "Save the uploaded image to database.",
response = String.class)
#ApiResponses(value = {
#ApiResponse(code = 200, message = "The uploaded image has been saved.", response = String.class),
#ApiResponse(code = 500, message = "Error while trying to resize the image.<p>Internal error code: 2103", response = a.b.ErrorInfo.class)})
#Override
public String uploadImage(
#ApiParam(value = "file to upload", required = true) #FormDataParam("file") final InputStream inputStream,
#ApiParam(value = "details of the uploaded file", required = true) #FormDataParam("file") final FormDataContentDisposition fileDetail) {
//return UUID.randomUUID().toString();
}
I would like to add the following info to the API documentation in order to describe the content of the response string:
"The unique id of the uploaded image."
I have checked the ApiResponses documentation but I have not found anything related to this topic.
I can put this info next to the ApiResponse HTTP 200 but I am not sure whether this solution is correct or not.

From my experience with swagger, I think it must be specified in the notes field in the ApiOperation like below
#ApiOperation(
value = "Save an image",
notes = "Returns the unique id of the uploaded image",
response = String.class)

Related

FeignClient API with different response class

I am using Jhipster. I have a yaml file, then generate java code using jhipster openapi-client. It generate several files, including the all the model class needed (to contain the request and response).
DefaultApiClient
#FeignClient(name="${default.name:default}", url="${default.url:https://test.api.com/testing}", configuration = ClientConfiguration.class)
public interface DefaultApiClient extends DefaultApi {
}
DefaultApi
#javax.annotation.Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2021-01-22T14:50:31.377193700+08:00[Asia/Singapore]")
#Validated
#Api(value = "Default", description = "the Default API")
public interface DefaultApi {
/**
* POST /req/v1 : This is the request
*
* #param authorization JWT header for authorization (required)
* #param body (required)
* #return successful operation (status code 200)
* or server cannot or will not process the request (status code 400)
*/
#ApiOperation(value = "This is the request", nickname = "Verification", notes = "", response = ResponseType.class, authorizations = {
#Authorization(value = "clientID")
}, tags={ })
#ApiResponses(value = {
#ApiResponse(code = 200, message = "successful operation", response = ResponseType.class),
#ApiResponse(code = 400, message = "server cannot or will not process the request", response = ServiceMessagesType.class) })
#RequestMapping(value = "/req/v1",
produces = "application/json",
consumes = "application/json",
method = RequestMethod.POST)
ResponseEntity<ResponseType> Verification(#ApiParam(value = "JWT header for authorization" ,required=true, defaultValue="Bearer REPLACE_THIS_KEY") #RequestHeader(value="Authorization", required=true) String authorization,#ApiParam(value = "" ,required=true ) #Valid #RequestBody RequestType body);
}
I can manage to get the response successfully, but the problem appear when I send a false request, It will response with and Bad Request 400 and crash my program.
As you can see on the swagger annotation #ApiResponse, it return different class.
I am really confuse with it. My question is:
Just for confirm, #ApiResponse is only for documentation, right? Does this code affect the program like when it return code 400, the response will automatically be ServiceMessageType class?
How can I handle different response class? As you can see in the function deffinition, ResponseEntity Verification, it will return ResponseType as the body of ResponseEntity. But when I send an error request to this Api, this Api will return ServiceMessageType. And fyi, the code 400 will give my program an error says "failed and no fallback available" so I think I need an error handle to do it.
For no.2, I already search for the solution in several source
https://programmer.group/feign-call-error-failed-and-no-fallback-available.html
but I don't really get it. I use the fallbackFactory, and it can handle the 400 code exception. But I still really confuse about how to return different response class. And I get the result not in correct structure, as the link said:
By implementing FallbackFactory, you can get the exception thrown by the service in the create method. However, please note that the exception here is encapsulated by Feign, and the exception thrown by the original method cannot be seen directly in the exception information. The abnormal information obtained is as follows: status 500 reading TestService#addRecord(ParamVO); content: {"success":false,"resultCode":null,"message":"/ by zero","model":null,"models":[],"pageInfo":null,"timelineInfo":null,"extra":null,"validationMessages":null,"valid":false}
To illustrate, in this example, the interface return information of the service provider will be uniformly encapsulated in the user-defined class Result, and the content is the above content: {"success":false,"resultCode":null,"message":"/ by zero","model":null,"models":[],"pageInfo":null,"timelineInfo":null,"extra":null,"validationMessages":null,"valid":false}
Please explain to me how it work, or you can give me a link about how it works, I will really appreciate the help.

Unable to post multipart data and requestbody form data json request

Im trying to post data from postman. I have an method receiving RequestBody and Multipart file. But im steel having this error. The way i use to store images, is working in other implementations when i save only one image.
{
"timestamp": "2020-02-06T19:52:12.566+0000",
"status": 415,
"error": "Unsupported Media Type",
"message": "Content type 'multipart/form-data;boundary=--------------------------833603313116090653834108;charset=UTF-8' not supported",
}
#PostMapping(value = "new", headers=("content-type=multipart/*"), consumes = "multipart/form-data" )
private Product save(#RequestBody Product product, #RequestParam("files") MultipartFile[] files){
var disk = new Disk("product");
Product productSaved = new Product();
String fileName;
try {
if (files != null && files.length >0) {
productSaved = service.save(product);
for (MultipartFile file : files) {
fileName = disk.saveImage(file);
Images image = new Images(fileName, productSaved);
imagesService.saveImage(image);
}
} else {
return null;
}
} catch (IOException e) {
e.printStackTrace();
}
return productSaved;
}
The first thing is the MultipartFile cannot be inside the body of the Response from your client. The second thing is the data response from your browser should only be only one way.
My suggestion is you can put all the data you want to save to the database inside a form submission. And use #ModelAttribute Product product, #RequestParam MultipartFile[] files .
Also, your method can be void since you save data, you don't need to return anything.
Note: #ModelAttribute can be omitted.
You can take both params as RequestParam and covert json body to Object using objectMapper like below

How to generate file chooser in Swagger-ui for body inpustream

Hello i have the following jaxrs entry
#PUT()
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_OCTET_STREAM)
#ApiOperation(value = "Bla bla.")
#Path("secure/flappy")
public Response testput(
#ApiParam(value = "pwet",type = "file",format = "binary", required = true) InputStream certificate) throws Throwable {
try (InputStream stream = certificate) {
//Consume stream
return Response.ok().build();
}
}
And the generated swagger-ui page for this entry
I would like to know how to document my paremeter for getting only one parameter presented as a file chooser in swagger-ui.
#sdc: You're right i had to use multi part form data for getting a working file chooser in Swagger-ui. I also had to use #ApiImplicitParam for getting it working.
#PUT()
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.MULTIPART_FORM_DATA)
#ApiOperation(value = "Bla bla.")
#Path("secure/flappy")
#ApiImplicitParams({
#ApiImplicitParam(name = "file", value = "bla bla.", required = true, dataType = "java.io.File", paramType = "form")
})
public Response testput(#ApiParam(hidden = true) #FormDataParam("file") final InputStream certificate
) throws Throwable {
//TODO do something
return Response.ok().build();
}
I am not very familiar with Swagger UI, but this thread might be helpful
https://github.com/swagger-api/swagger-ui/issues/72
I see an example using an#ApiParam annotation
and this post talks about a file upload with the
def uploadFile annotation
https://github.com/swagger-api/swagger-ui/issues/169
#PUT
#Path("/secure/flappy")
#Consumes(Array(MediaType.MULTIPART_FORM_DATA))
#ApiOperation(value = "test a put file upload")
def uploadFile(
#ApiParam(value = "file to upload", required=false) #FormDataParam("file") inputStream: InputStream,
#ApiParam(value = "file detail") #FormDataParam("file") fileDetail: FormDataContentDisposition) = {
val uploadedFileLocation = "./" + fileDetail.getFileName
IOUtils.copy(inputStream, new FileOutputStream(uploadedFileLocation))
val msg = "File uploaded to " + uploadedFileLocation + ", " + (new java.io.File(uploadedFileLocation)).length + " bytes"
val output = new com.wordnik.swagger.sample.model.ApiResponse(200, msg)
Response.status(200).entity(output).build()
}
I suppose you need to use in the parameter description following:
#RequestPart("file") MultipartFile file
At least for me it gives a swagger form with a file selection button.
The solution was found in the examples here:
https://github.com/springfox/springfox-demos

Render thumbnail in Angular4

I am trying to render an image which I got from a Java service as InputStream, re-send it through NodeJS Express server and finally render it in Angular4
Here's what I do:
Java Jersey service:
#GET
#Path("thumbnail")
#ApiOperation(
value = "Gets document preview",
notes = "Gets document preview"
)
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Preview of the document")
})
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces("image/png")
public Response getDocThumbnail(
#ApiParam(value = "Entity UUID", required = true) #FormDataParam("uuid") String uuid
) throws RepositoryException, UnknowException, WebserviceException, PathNotFoundException, DatabaseException, AutomationException, AccessDeniedException, ConversionException, IOException {
RawDocument rawDocument = docCtrl.getDocThumbnail(uuid);
return Response
.ok(rawDocument.getInputStream(), "image/png")
.header("Content-Disposition", "attachment; filename=\" " + rawDocument.getName() + "\"")
.build();
}
the controller looks like:
public RawDocument getDocThumbnail(String uuid) throws IOException, AccessDeniedException, PathNotFoundException, WebserviceException, RepositoryException, DatabaseException, ConversionException, AutomationException, UnknowException {
return new RawDocument(
okmWebSrv.getOkmService().getThumbnail(uuid, ThumbnailType.THUMBNAIL_LIGHTBOX),
"whatever"
);
}
Basically it's call to OpenKM SDK to retreive document's thumbnail
This Java endpoint is called from NodeJS Express 4.15 that is pre-processing some requests for this Java backend.
Here's what I do:
...compose request options...
const vedica_res = await rp(options);
let buffered = new Buffer(vedica_res, 'binary');
res.writeHead(200, {
'Content-Type': 'image/png',
'Content-disposition': 'attachment;filename=' + 'thumb.png',
'Content-Length': buffered.length
});
return res.end(buffered, 'binary');
Finally with Angular4 being the initiator of this roundtrip I am trying to render the image like so:
this.rest.send('http://localhost:4200/vedica/api/document/thumbnail', RequestMethod.Get,
{uuid: '19516ea1-657e-4b21-8564-0cb87f29b064'}, true).subscribe(img => {
// this.preview = img
var urlCreator = window.URL;
var url = urlCreator.createObjectURL(img);
this.thumb.nativeElement.src = url;
})
The 'img' received is a Blob {size: 81515, type: "image/png"}. Console shows no errors but renders no image in the <img #thumb/> tag. But I can see that it sets the src=blob:http%3A//localhost%3A3000/4cf847d5-5af3-4c5a-acbc-0201e60efdb7 for it. Image just has a broken image icon.
When I try to read a cached response in a new tab, its accessible but renders nothing again.
Can you point out what I'm doing wrong? Have tried a lot, but no luck.
I think the problem is not the stream is closed early, the problem I think will be in the way is downloaded, take a look here:
https://docs.openkm.com/kcenter/view/sdk4j-1.1/document-samples.html#getContent
From the server side ( inde middle between OpenKM and your user interface ) the problem usualy is:
//response.setContentLength(is.available()); // Cause a bug, because at this point InputStream still has not its real size.
And you should use
response.setContentLength(new Long(doc.getActualVersion().getSize()).intValue());
resolved this by replacing request-promise with bare request package for making this request to the java BE and piping reply right into the wrapping response of the angular FE:
let reply = request(options);
reply.pipe(res);

Swagger UI and Play routing *path

I'm having trouble with Swagger understanding Play! 2.0 routing wildcard routing, so the swagger ui ends up with broken URL.
My routes file has this route:
GET /settings/api/:project/*path #controllers.API.getParams(project, path)
Then my Controller has the following code:
#ApiOperation(value = "Returns settings for given project and path.", response = String.class, httpMethod = "GET")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Request completed successfully."),
#ApiResponse(code = 500, message = "Internal error while processing request")
})
#ApiImplicitParams({
#ApiImplicitParam(name = "project", value = "Project name", required = true, dataType = "String", paramType = "path"),
#ApiImplicitParam(name = "path", value = "path", required = true, dataType = "String", paramType = "path")
})
public Result getParams(String project, String path) {
return ok(path);
}
Then when Swagger UI gets rendered, I see the path for this action rendered as
POST /settings/api/{project}/{path<.+>
And when I do a call it turns into
/settings/api/test/{path<.+>
So basically the :project gets replaced but the *path remains broken/intact.
Please share if you know how to fix this. Thanks!
So turns out that swagger doesn't support wildcard routes.

Categories

Resources