DEV Community

Felipe Henrique Gross Windmoller
Felipe Henrique Gross Windmoller

Posted on

Uploading a file through Swagger in Quarkus

In this project I show a way where you can upload a file through the SWagger-UI in Quarkus.

Maximillian Arruda showed me how to to this and I decided to create this project to help other people who might also want to use this feature.

How it works

Start the application with:

./mvnw compile quarkus:dev
Enter fullscreen mode Exit fullscreen mode

Access the swagger-ui at http://localhost:8080/q/swagger-ui and add the files you want to upload (the assets folder has two files for test):
Swagger-ui uploading files

Click execute.

You'll receive one 202 Accepted.

The application sends the Buffer from the files to a Vert.X Bus Event, where they are processed and the information is displayed.

In the developer are of the browser (usually when you press F12), you can see the HTTP POST request with all data being sent to the server:
Image description

In the logs of the application, you'll see that the HTTP endpoint is provided by by one executor thread and the processing of the file is done by one worker thread:
Image description

Under the hood

This Java class does all the magic of the swagger-ui and send the events to the Vert.X event bus:

package org.acme;

import java.io.BufferedReader;
import java.io.IOException;
import java.nio.file.Files;
import java.util.List;

import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
import org.jboss.logging.Logger;
import org.jboss.resteasy.reactive.MultipartForm;
import org.jboss.resteasy.reactive.RestForm;
import org.jboss.resteasy.reactive.multipart.FileUpload;

import io.vertx.core.eventbus.EventBus;

@RequestScoped
@Path("upload")
public class UploadResource {

    private static final Logger LOG = Logger.getLogger(UploadResource.class.getName());

    @Inject
    EventBus bus;

    @POST
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    @APIResponse(responseCode = "202")
    public Response upload(
            @MultipartForm MultipartBody body) throws IOException {

        LOG.info("upload() quantity of files + " + body.files.size());

        for (FileUpload file : body.files) {

            LOG.info("filePath " + file.filePath());

            BufferedReader br = Files.newBufferedReader(file.filePath());

            bus.send("file-service", br);
        }

        LOG.info("upload() before response Accepted");

        return Response
                .accepted()
                .build();
    }

    // Class that will define the OpenAPI schema for the binary type input (upload)
    @Schema(type = SchemaType.STRING, format = "binary")
    public interface UploadItemSchema {
    }

    // Class that will be used to define the request body, and with that
    // it will allow uploading of "N" files
    public class UploadFormSchema {
        public List<UploadItemSchema> files;
    }

    // We instruct OpenAPI to use the schema provided by the 'UploadFormSchema'
    // class implementation and thus define a valid OpenAPI schema for the Swagger
    // UI
    @Schema(implementation = UploadFormSchema.class)
    public static class MultipartBody {
        @RestForm("files")
        public List<FileUpload> files;
    }

}

Enter fullscreen mode Exit fullscreen mode

This class consumes the events from the event bus and displays the data:

package org.acme;

import java.io.BufferedReader;
import java.io.IOException;

import javax.enterprise.context.ApplicationScoped;

import org.jboss.logging.Logger;

import io.quarkus.vertx.ConsumeEvent;

@ApplicationScoped
public class FileService {

    private static final Logger LOG = Logger.getLogger(FileService.class.getName());

    @ConsumeEvent(blocking = true, value = "file-service")
    public void processFile(BufferedReader br) throws InterruptedException {

        LOG.info("processFile() begin");

        try (br) {
            String currentLine = null;
            while ((currentLine = br.readLine()) != null) {
                LOG.info("currentLine " + currentLine);
            }
        } catch (IOException e) {
            LOG.error("Error", e);
        }

        LOG.info("processFile() end");

    }

}
Enter fullscreen mode Exit fullscreen mode

Thanks for reading!

Top comments (2)

Collapse
 
dearrudam profile image
Maximillian Arruda

Great article!!! Congratulations!!! And thanks for mentioning me!!! 👍🙂

Collapse
 
felipewind profile image
Felipe Henrique Gross Windmoller

Thanks for helping!