How to create an Open API 3.0.1 Specification - spring-boot

I am new to swagger documentation etc
Please, could you share any good resource or steps for creating an open api spec for the following endpoint, which is an endpoint of a spring boot microservice:
#PostMapping(path = "/pdf", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<ByteArrayResource> createReport(#RequestParam MultipartFile template, #RequestParam MultipartFile templateDataAsJson) throws IOException {
log.info("Triggering PDF Generation and Download");
log.info("Step 1 Starts : Sending Json data to the template data binder microservice: Request:{}", templateDataAsJson);
String completedHtmlJson = restClient.populateTemplate(template, templateDataAsJson);
log.info("Steps 2 Starts: Sending populated html template to html-to-pdf microservice for rendering:{}", completedHtmlJson);
ResponseEntity<ByteArrayResource> response = restClient.html2PdfGeneration(completedHtmlJson);
return ResponseEntity.ok().contentType(APPLICATION_PDF).body(response.getBody());
}
Any help or references will be appreciated.
Thanks all.

You can look at SpringDoc
https://github.com/springdoc/springdoc-openapi
It will generate the documentation on the fly for for you.

Related

call api to upload file with metadata using feign client

I created a simple api to upload a file with its metadata using spring boot, the api works fine without any problems, here is the controller :
#PostMapping(value="/v1/docs", consumes=MediaType.MULTIPART_FORM_DATA_VALUE)
public String uploadFile(#ModelAttribute MetaData metadata, #RequestParam("file") MultipartFile file){
// upload file logic ...
return "id";
}
you can see how I call this api using postman :
I deployed this api and now I want to call it in another service (developed also by spring boot), I should use feing client to do this call, so I created a simple feign client :
#FeignClient(name = "docsClient", url="<host_url>")
public interface DocsClient{
#PostMapping(value="/v1/docs", consumes=MediaType.MULTIPART_FORM_DATA_VALUE)
String uploadFile(#RequestParam("file") MultipartFile file, #ModelAttribute MetaData metadata);
}
the proleme is when I call DocsClient.uploadFile, I got an error (415, unsupported mediaType) from the deployed service, when I log the request I found that the depoloyed service get the request like this :
POST /v1/docs?file=<value_of_file>
normally It should not include file or metadata at the url, but it should include it as --form instead:
--form "key=value"
How can I solve this issue?
The order of parameters matter, when creating the client you should respect the order :
#FeignClient(name = "docsClient", url="<host_url>")
public interface DocsClient{
#PostMapping(value="/v1/docs", consumes=MediaType.MULTIPART_FORM_DATA_VALUE)
String uploadFile( #ModelAttribute MetaData metadata, #RequestParam("file") MultipartFile file);
}

How to migrate this mutlipart file upload to Spring Boot 2.4?

With Spring Boot 2.3 I was using the following Kotlin code
val mvcResultImage = this.mockMvc!!.perform(MockMvcRequestBuilders.multipart("/somepath)
.file("files[]", imageFile.getBytes())
.characterEncoding("UTF-8"))
.andReturn()
in an integration test for a controller with a function
#PostMapping(path = ["/somepath"],
consumes = [MediaType.MULTIPART_FORM_DATA_VALUE],
produces = [MediaType.APPLICATION_JSON_VALUE])
#ResponseBody
fun createFromBytes(#RequestParam("files[]") file: MultipartFile): ResponseEntity<Any> {
...
}
In 2.3 I was able to handle the request in the controller function whereas in 2.4 the controller function raises a org.springframework.web.multipart.support.MissingServletRequestPartException with the message Required request part 'files[]' is not present and causes HTTP response code 400.
I don't find anything in the migration guide and list of handled issues for this version change.
A rename to file in both controller and request doesn't help, I don't remember why I added [] in the code working with 2.3, but I think it was necessary to make it work.
I'm using Spring Boot through the maven parent mechanism with spring-boot-starter-parent:2.4.1.
This is a known issues in Spring Boot coming from Spring. It's fixed in Spring Boot 2.4.2. The linked issue contains a successfully tested workaround in case you're stuck with 2.4.1: Create MockMultipartFile with MockMultipartFile( String name, #Nullable String originalFilename, #Nullable String contentType, #Nullable byte[] content) (specification of originalFilename matters).

Resolving POST /** request URL to full request URL using micrometer

With the micro-service architecture I have written a generic POST request handler which is consumed by all the micro-services. The post mapping in spring look like this:
#RestController
#RequestMapping(value = "/v1/", consumes = {MediaType.APPLICATION_JSON_VALUE}, produces = {MediaType.APPLICATION_JSON_VALUE})
public class V1Controller {
#PostMapping(path = "/**")
public #ResponseBody Json post () {}
}
Now while I am consuming the metrics for this endpoint using micrometer I am only getting /v1/ as the endpoint in the metrics while I am sending the full URL like /v1/demo/foo from the calling service. I tried lot of the combination but it is not working. I have also added the WebMvcTagsProvider where I am listing to request and resolving the POST api calls.
#Bean
#SuppressWarnings("unchecked")
public WebMvcTagsProvider webMvcTagsProvider(ObjectMapper objectMapper) {
return new DefaultWebMvcTagsProvider() {
public Iterable<Tag> getTags(HttpServletRequest request, HttpServletResponse response, Object handler, Throwable exception) {
if ("POST".equals(request.getMethod())) {
Tag uriTag = Tag.of("uri", String.valueOf(request.getRequestURI()));
return Tags.of(WebMvcTags.method(request), uriTag, WebMvcTags.exception(exception), WebMvcTags.status(response));
}
return Tags.of(WebMvcTags.method(request), WebMvcTags.uri(request, response), WebMvcTags.exception(exception), WebMvcTags.status(response));
}
};
}
Still it is resolving to /v1/ URL in the metrics. I tried googling alot but didn't find any solution. Thanks in advance.
The build in Spring Boot RequestMapping based metrics match on the annotations and add those as tags.
This is to avoid a tag explosion. Imagine a #RequestMapping for a path like user/{userId}, you would want to group all those calls together (user/1, user/2, user/3).
You'll want to create your own Timer in your post method that set that url tags, etc there.
If you decide to reuse the same metric name as the built in Spring Boot metric, you'll want to disable that one as well, so you don't double count those requests.

How to enable Spring Reactive Web MVC to handle Multipart-file?

I'm trying to use the new reactive web-mvc implementation in a spring boot 2.0 application. I'm trying to define a method which consume multipart file but do not succeed at making it working :( - I always get a 415 error.
On one hand I have a controller containing the following request mapping :
#RequestMapping(method = RequestMethod.POST, path = "/myPath/{param}/{param2}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
#ResponseBody
public Mono<Void> postFile(
#RequestBody MultipartFile data,
#PathVariable("param") String param,
#PathVariable("param2") String param2,
#RequestHeader(name = HEADER_DATE, required = false) #DateTimeFormat(pattern = DATE_FORMAT) Instant instant
){
return fileService.handleData(Mono.just(data), param, param2, instant);
}
On the other hand I had to add a server on the top of the basic dependencies as it seems netty do not handle multipart files. I so added the spring-boot-starter-tomcatdependency which enabled the MultipartAutoConfiguration to be matched and satisfied on application auto configuration.
When posting something using a curl call :
curl 'Meta-Date: 20170101104532' --form "file=#file.bin" http://localhost:8082/myPath/foo/bar
while debug logs are activated (logging.level.org.springframework.web=DEBUG) I got this exception :
org.springframework.web.server.UnsupportedMediaTypeStatusException: Request failure [status: 415, reason: "Content type 'multipart/form-data;boundary=------------------------58fa43b8f1a26de4' not supported"]
This error is thrown by the RequestBodyArgumentResolver which has the the following supported media types : [*/*, text/xml, application/*+json;charset=UTF-8, application/xml, text/plain;charset=UTF-8, application/x-www-form-urlencoded, application/json;charset=UTF-8] provided by 9 DecoderHttpMessageReader.
Before posting I also took a look at :
Spring MultiPart MediaType Unsupported which seems to not be relevant here as my autoconf report contains the following entry : MultipartAutoConfiguration#multipartResolver matched
set content-type to utf-8 with angularjs $http Adding a header setting Content-Transfer-Encoding: binary didn't changed anything.
My understanding is that Spring web 5.0 uses a new request decoder system as I don't find these classes on a spring 4 spring boot application, and there is not yet any DecoderHttpMessageReader dealing with multipart file
Did I miss something ? Or should I wait one to be implemented ?
Okay, It seems this is just not implemented for now as it currently exists a pull request for this feature : Add reactive multipart request support #1201
Should have check this earlier...
[EDIT] : The issue has been solved and merged into Spring master branch. Should no longer be an issue.
#PutMapping(value="/{..}",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Mono<Void> save(#RequestPart("file") FilePart multipartFormData,#RequestParam("fileName") String fileName,#PathVariable("..") String ..) throws IOException {
List<ByteBuffer> bytesList = new LinkedList<>();
multipartFormData.content().
subscribe(item->bytesList.add(item.asByteBuffer()));
int totalBytes = bytesList.stream().mapToInt(item->item.capacity()).sum();
ByteBuffer buffer = ByteBuffer.allocate(totalBytes);
bytesList.stream().forEach(byteBuff->buffer.put(byteBuff));
baseImageHandler.saveImage(buffer, fileName, baseItemId);
return Mono.empty();
}
Please note that it is a dev verison, but this is how I have managed to do it.

Spring Boot - Writing media (image, mp3, mp4) file to response output stream

I am new to Servlets and Spring Framework.
I try to get media files from directory through Rest Service.
For videos/mp4 I couldn't find anything.
For audio I did this:
Writing mp3 file to response output stream
For images I did this:
#RequestMapping("/tmp/{uuid}")
#ResponseBody
public ResponseEntity<InputStreamResource> getTmp(#PathVariable("uuid") String uuid)
throws IOException {
Path path = Paths.get("/media/psmaster/HDD/TUC-IPS/" + uuid);
String contentType = Files.probeContentType(path);
FileSystemResource file = new FileSystemResource("/media/psmaster/HDD/TUC-IPS/" + uuid);
return ResponseEntity
.ok()
.contentLength(file.contentLength())
.contentType(
MediaType.parseMediaType(contentType))
.body(new InputStreamResource(file.getInputStream()));
}
Can someone please help to figure out the problem?
If you are using Spring 4.2 you can use StreamingResponseBody, Have a look at this post
You can also give Spring Content a look. It allows you to build content services very quickly and easily using similar programming techniques to Spring Data. You can also pair it with Spring Data to additionally store and search metadata for your videos. By defining a single interface and including the appropriate Spring Content dependency in your project you can create a set of REST endpoints that allow you to manage the full lifecycle of a video including streaming.
You can write media using streams and HttpServletResponse:
#RequestMapping(value = "/image/{imgName}", method = RequestMethod.GET)
public void getImageAsByteArray(#PathVariable String imgName , HttpServletResponse response) throws IOException {
InputStream in = servletContext.getResourceAsStream("/WEB-INF/images/" + imgName);
response.setContentType(MediaType.IMAGE_JPEG_VALUE);
IOUtils.copy(in, response.getOutputStream());
}
The example above serves an image file.
Hope this helps

Resources