我正在构建一个用于上传文件的 Quarkus REST API,并且我想在开发过程中使用 Swagger UI,以便在开发网站时拥有紧密的反馈循环。然而,我正在努力让 Swagger UI 优雅地格式化文件输入。
我尝试按照 RESTEasy Reactive 指南 获取有关如何接受文件作为路由响应正文的说明,但我似乎无法让 Swagger UI 将输入显示为除大文本字段之外的任何内容。这是通过 Swagger UI 查看的 Quarkus 2.14 示例。
在开发 API 之前,我已经熟悉了 Swagger UI 中的文件上传提示,如此处位于 Swagger 文档所示。文件上传提示允许最终用户选择任意文件(二进制或文本)进行上传。我希望我应该能够向 Swagger UI 传达我希望将此字段视为文件而不是文本。
这是一个错误还是我需要一些额外的元数据来为该 API 的输入选择更合适的视图?
我正在使用 Quarkus 2.14,只需使用 Quarkus RESTEasy 指南中的示例即可重现该问题。
Quarkus 扩展:
<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路线:
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) {
}
}
渲染的 OpenAPI 文档:
---
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 发现了一个相关的 Quarkus 问题,帮助确定了我的问题的解决方法。经过一些修改,我能够上传单个文件,同时在 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) {
}
}
这有点棘手。
下面是 Quarkus Reactive 和 Kotlin 的示例
import jakarta.ws.rs.Consumes
import jakarta.ws.rs.POST
import jakarta.ws.rs.Path
import jakarta.ws.rs.Produces
import jakarta.ws.rs.core.MediaType
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType
import org.eclipse.microprofile.openapi.annotations.media.Schema
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter
import org.eclipse.microprofile.openapi.annotations.tags.Tag
import org.jboss.resteasy.reactive.RestForm
import org.jboss.resteasy.reactive.multipart.FileUpload
import java.io.File
@Tag(name = "Upload")
@Path("/fn/upload")
class FileUploadHandler {
@Schema(type = SchemaType.STRING, format = "binary")
internal class UploadItemSchema
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.MULTIPART_FORM_DATA)
fun handleUploadRequest(
@Schema(implementation = UploadItemSchema::class)
@Parameter(
name = "file",
description = "The file to upload"
)
@RestForm("file") file: FileUpload
): Map<String, Any> {
val info = mutableMapOf<String, Any>()
info["fileName"] = file.fileName()
info["filePath"] = file.filePath().toString()
info["contentType"] = file.contentType()
info["size"] = file.size()
if (!file.uploadedFile().toFile().renameTo(File("logs/${file.fileName()}"))) {
throw InternalError("Could not move uploaded file")
}
return info
}
}
您需要这个
UploadItemSchema
类和 @Schema
注释。
另外不要忘记设置@Consumes(MediaType.MULTIPART_FORM_DATA)
在这种情况下,会生成正确的 openapi:
/fn/upload:
post:
tags:
- Upload
operationId: handleUploadRequest
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
file:
$ref: '#/components/schemas/UploadItemSchema'
responses:
"200":
description: OK
content:
application/json:
schema:
type: object
additionalProperties: {}
架构:
UploadItemSchema:
format: binary
type: string