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
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):
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:
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
:
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;
}
}
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");
}
}
Thanks for reading!
Top comments (2)
Great article!!! Congratulations!!! And thanks for mentioning me!!! 👍🙂
Thanks for helping!