Quarkus REST API中如何在@RequestBody的OpenAPI标签指定多实现类
问题
我有一个Quarkus REST API,接收多种JSON格式的事件并转发至Kafka主题。希望在OpenAPI契约中自动生成这些JSON的结构,无需手动编写。目前已通过@RequestBody标签指定单个实现类(如Application.class),但需同时支持CourseEnrollment.class等多种事件类型,现咨询实现方案。
当前API端点代码示例:
@POST @Path("/student") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) @Tag(name = "Student Events Service") @Operation(summary = "Accepts student type events", description = "Accepts student type events") @APIResponse(responseCode = "200", description = "Event sent successfully") @APIResponse(responseCode = "400", description = "The JSON packet sent did not conform to any known message or the primary key or shared data in the packet is invalid. \n " + "See Response Body for detail. - " + "Error code 400-1 = Bad message structure or unknown message. Log error and continue to next message - " + "Error code 400-2 = Bad primary key. Fix data (client or server side) and retry later - " + "Error code 400-3 = Invalid shared data. Fix shared data and retry later", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class))) @APIResponse(responseCode = "500", description = "Unexpected server error. See Response Body for detail. - " + "Error code 500-1 = Unable to send to KAFKA, please wait and retry later - " + "Error code 500-2 = Unable to connect to verification database, please wait and retry later - " + "Error code 500-3 = General server error, Please wait and retry later", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class))) public Response postStudentEvent(String eventJSON) { // 业务逻辑 }
当前仅支持单个类的@RequestBody配置:
@RequestBody( required = true, content = @Content( schema = @Schema(implementation = Application.class) ) )
需支持的两类事件类代码:
public class CourseEnrollment { private String eventID; private String eventTime; private String eventType; private String eventUserSource; private String externalReference1; private String firstName; private String lastName; private String emailAddressPrimary; private String emailAddressAlternate; private String periodStartDate; private String periodEndDate; private String intakeIntakeYearCode; private String programmeCode; // getter/setter省略 } public class Application { private String eventID; private String eventTime; private String eventType; private String eventUserSource; private String eventTrigger; private ApplicationInfo applicationDetails = null; private Person personDetails = null; private School schoolDetails = null; // getter/setter省略 }
注:这些类均属于当前项目,外部系统生成事件JSON并发送至该REST服务,我需将其转发至本地Kafka主题。
解决方案
方案1:使用oneOf关键字实现多类型支持
直接在@Schema中通过oneOf属性指定所有支持的事件类,OpenAPI会自动生成包含所有类型结构的契约,明确说明请求体可以是这些类型中的任意一种。
修改@RequestBody配置如下:
@RequestBody( required = true, content = @Content( mediaType = MediaType.APPLICATION_JSON, schema = @Schema( oneOf = {Application.class, CourseEnrollment.class}, description = "支持的事件类型:Application或CourseEnrollment" ) ) )
方案2:抽象公共父类/接口
如果多个事件类有公共字段(比如eventID、eventTime),可以抽象出父类,让所有事件类继承它,再通过subTypes声明具体子类,契约结构会更清晰。
- 创建公共父类:
public abstract class BaseStudentEvent { private String eventID; private String eventTime; private String eventType; private String eventUserSource; // getter/setter }
- 修改事件类继承父类:
public class CourseEnrollment extends BaseStudentEvent { // 特有字段... } public class Application extends BaseStudentEvent { // 特有字段... }
- 配置
@RequestBody:
@RequestBody( required = true, content = @Content( mediaType = MediaType.APPLICATION_JSON, schema = @Schema( implementation = BaseStudentEvent.class, subTypes = {Application.class, CourseEnrollment.class}, description = "支持的学生事件类型" ) ) )
方案3:拆分独立端点(可选)
如果业务允许,可将不同类型的事件拆分为独立API端点,每个端点单独配置对应的请求体类型,契约更直观,但会增加端点数量。
示例:
@POST @Path("/student/application") @RequestBody( required = true, content = @Content(schema = @Schema(implementation = Application.class)) ) public Response postApplicationEvent(Application application) { // 转发到Kafka逻辑 } @POST @Path("/student/course-enrollment") @RequestBody( required = true, content = @Content(schema = @Schema(implementation = CourseEnrollment.class)) ) public Response postCourseEnrollmentEvent(CourseEnrollment enrollment) { // 转发到Kafka逻辑 }
内容的提问来源于stack exchange,提问作者Elmar Matthee
相关产品推荐
相关产品推荐

