Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to provide swagger annotation for MultipartFormDataInput in RestEasy with Quarkus

while working on Quarkus with the RestEasy framework, I have the functionality to upload a file using MultipartFormDataInput. This functionality is working as expected, but I am unable to provide proper open API annotation for swagger UI. I have tried multiple options and combinations, but it did not bear fruit. Please help me. I provide below the sample code.

@Operation(summary = "Upload a single file", description = "Upload a single file")
    @APIResponses({
            @APIResponse(responseCode = "200", description = "Upload file successfully"),
            @APIResponse(name = "500", responseCode = "500", description = "Internal service error") })
    @RequestBody(content = @Content(
            mediaType = MediaType.MULTIPART_FORM_DATA,
            schema = @Schema(type = SchemaType.STRING, format = "binary"),
            encoding = @Encoding(name = "attachment", contentType = "application/octet-stream")))
    @POST
    @Path("/singleFile")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    @Produces(MediaType.TEXT_PLAIN)
    public Response handleFileUpload(@MultipartForm MultipartFormDataInput input) {
        String fileName = null;

        Map<String, List<InputPart>> uploadForm = input.getFormDataMap();
        // Get file data to save
        List<InputPart> inputParts = uploadForm.get("attachment");
        for (InputPart inputPart : inputParts) {
            try {
                MultivaluedMap<String, String> header = inputPart.getHeaders();
                fileName = getFileName(header);
                InputStream inputStream = inputPart.getBody(InputStream.class, null);
                byte[] bytes = IOUtils.toByteArray(inputStream);
                File customDir = new File(UPLOAD_DIR);
                if (!customDir.exists()) {
                    customDir.mkdir();
                }
                fileName = customDir.getCanonicalPath() + File.separator + fileName;
                Files.write(Paths.get(fileName), bytes, StandardOpenOption.CREATE);
                return Response.status(200).entity("Uploaded file name : " + fileName).build();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return Response.status(200).entity("Uploaded file name : " + fileName).build();
    }

I have also referred to the following links.

https://community.smartbear.com/t5/Swagger-Open-Source-Tools/How-to-swagger-annotate-multipart-form-data-with-resteasy/td-p/178776

https://github.com/swagger-api/swagger-core/issues/3050

I am able to generate swagger UI if I create a separate class called MultipartBody with @Schema(type = SchemaType.STRING, format = "binary") and @PartType(MediaType.APPLICATION_OCTET_STREAM) annotation. But my requirement is to use only MultipartFormDataInput.

like image 220
Sambit Avatar asked Sep 26 '20 16:09

Sambit


1 Answers

You were almost there :) Just use a dedicated class in your RequestBody/Schema and tell OpenAPI ignore the params of your method.

@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@RequestBody(content = @Content(mediaType = MediaType.MULTIPART_FORM_DATA,
    schema = @Schema(implementation = MultipartBody.class))
)
@Operation(operationId = "uploadFile")
public Response uploadFile(@Parameter(hidden = true) MultipartFormDataInput input) {
//... your logic here
}

Two things to note: @Parameter(hidden = true) tells Smallrye OpenAPI to not consider your MultipartFormDataInput when generating Schema model. Then you need to tell describe the schema explicitly, using @RequestBody, where MultipartBody is a class that describes all your input params(you can add more params there if you want to for example pass other props along with the file payload)

public class MultipartBody {

    @FormParam("file")
    @Schema(type = SchemaType.STRING, format = "binary", description = "file data")
    public String file;


    @FormParam("fileName")
    @PartType(MediaType.TEXT_PLAIN)
    public String fileName;
}

Just make sure that the @FormParam annotated fields in the MultipartBody match the ,,parts" that you expect to find in your MultipartFormDataInput - e.g. in your case the file attribute should have @FormParam("attachment")

like image 149
yntelectual Avatar answered Sep 22 '22 21:09

yntelectual