I'm working on building a Quarkus REST API for uploading files and I'd like to use the Swagger UI while developing to have a tight feedback loop as I develop the site. However I'm struggling to get Swagger UI to format the file input elegantly.
I've tried to follow the RESTEasy Reactive guide for instruction on how to accept a file as a response body for a route but I can't seem to get Swagger UI to display the input as anything but a large text field. Here is the Quarkus 2.14 example as seen through the Swagger UI.
While developing APIs before I've grown familiar with a file upload prompt in the Swagger UI as shown here in Swagger docs. The file upload prompt allows an end user to select any arbitrary file (binary or text) to upload. I'd expect I should be able to convey to Swagger UI that I'd like this field treated as a file instead of text.
Is this a bug or do I need some extra metadata to pick a more appropriate view for this API's inputs?
I'm using Quarkus 2.14 and am able to reproduce the issue simply using the example found in the Quarkus RESTEasy guide.
Quarkus Extensions:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-openapi</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-swagger-ui</artifactId>
</dependency>
RESTEasy Route:
package com.me.example;
import javax.enterprise.context.RequestScoped;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import org.jboss.resteasy.reactive.PartType;
import org.jboss.resteasy.reactive.RestForm;
import org.jboss.resteasy.reactive.multipart.FileUpload;
@Path("/files")
@RequestScoped
public class ExampleResource {
public static class Person {
public String firstName;
public String lastName;
}
@POST
public void multipart(@RestForm String description,
@RestForm("image") FileUpload file,
@RestForm @PartType(MediaType.APPLICATION_JSON) Person person) {
}
}
Rendered OpenAPI document:
---
openapi: 3.0.3
info:
title: API
version: 0.1.0-SNAPSHOT
paths:
/files:
post:
tags:
- Example Resource
requestBody:
content:
application/x-www-form-urlencoded:
schema:
type: object
properties:
description:
type: string
image:
$ref: '#/components/schemas/FileUpload'
person:
$ref: '#/components/schemas/Person'
encoding:
person:
contentType: application/json
responses:
"201":
description: Created
components:
schemas:
FileUpload:
type: object
Person:
type: object
properties:
firstName:
type: string
lastName:
type: string
Helen found a relevant Quarkus issue that helped identify a workaround to my issue. With some modifications I was able to get a single file to upload while maintaining the intuitive file picker interface in Swagger UI.
package com.me.example;
import javax.enterprise.context.RequestScoped;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.jboss.resteasy.reactive.RestForm;
import org.jboss.resteasy.reactive.multipart.FileUpload;
@Path("/files")
@RequestScoped
public class ExampleResource {
@Schema(type = SchemaType.STRING, format = "binary")
public static class UploadItemSchema {
}
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
public void multipart(@RestForm("image") @Schema(implementation = UploadItemSchema.class) FileUpload file) {
}
}