1. 概述

在这个教程中,我们将讨论Swagger的@Operation@ApiResponse注解之间的主要区别。

2. 使用Swagger进行描述性文档

创建REST API时,为其编写适当的规范同样重要。此外,规范应该易于阅读、理解,并提供所有关键信息。而且,文档应描述对API所做的任何更改。手动创建REST API文档既耗时又累人。幸运的是,工具如Swagger可以帮助我们完成这个过程。

Swagger是一套围绕OpenAPI规范构建的开源工具,它能帮助我们设计、构建、文档化和使用REST API。

Swagger规范是为REST API文档的标准。使用Swagger规范,我们可以描述整个API,包括公开的端点、操作、参数、认证方法等。

Swagger提供了各种注解,帮助我们文档化REST API。更重要的是,它提供了@Operation@ApiResponse注解来为REST API文档化响应。在本教程的剩余部分中,我们将使用下面的控制器类,看看如何使用这些注解:

@RestController
@RequestMapping("/customers")
class CustomerController {

   private final CustomerService customerService;

   public CustomerController(CustomerService customerService) {
       this.customerService = customerService;
   }
  
   @GetMapping("/{id}")
   public ResponseEntity<CustomerResponse> getCustomer(@PathVariable("id") Long id) {
       return ResponseEntity.ok(customerService.getById(id));
   }
}

3. @Operation

@Operation注解用于描述单个操作。操作是路径和HTTP方法的独特组合。

此外,使用@Operation,我们可以描述REST API调用成功的结果。换句话说,我们可以使用此注解来指定一般的返回类型。

让我们将注解添加到我们的方法中:

@Operation(summary = "Gets customer by ID", 
           description= "Customer must exist")
@GetMapping("/{id}")
public ResponseEntity<CustomerResponse> getCustomer(@PathVariable("id") Long id) {
    return ResponseEntity.ok(customerService.getById(id));
}

接下来,我们将详细介绍@Operation中的某些常用属性。

3.1. summary 属性

summary属性是必需的,包含操作的摘要字段。简单来说,它提供了操作的简短描述。然而,我们应该确保这个参数长度不超过120个字符。

这是我们在@Operation注解中定义summary属性的方式:

@Operation(summary= "Gets customer by ID")

3.2. description 属性

使用description,我们可以提供有关操作的更多详细信息。例如,我们可以放置一个文本来描述端点的限制:

@Operation(summary= "Gets customer by ID", description= "Customer must exist")

3.3. hidden 属性

hidden属性表示此操作是否隐藏。

4. @ApiResponse

通常,我们使用HTTP状态码返回错误。我们可以使用@ApiResponse注解来描述操作可能的具体响应。

虽然@Operation注解描述了一个操作和一般的返回类型,而@ApiResponse注解则描述了其他可能的返回代码。

此外,该注解可以应用于方法级别和类级别。如果类级别的注解已经定义了与方法级别相同的代码的@ApiResponse,那么类级别注解将不会解析。换句话说,方法注解优先于类注解。

无论我们有一个还是多个响应,都应该在@ApiResponses注解内使用@ApiResponse注解。直接使用此注解将不会被Swagger解析。

现在,让我们在方法上定义@ApiResponses@ApiResponse注解:

@ApiResponses(value = {
        @ApiResponse(responseCode = 400, description = "Invalid ID supplied"),
        @ApiResponse(responseCode = 404, description = "Customer not found")})
@GetMapping("/{id}")
public ResponseEntity<CustomerResponse> getCustomer(@PathVariable("id") Long id) {
    return ResponseEntity.ok(customerService.getById(id));
}

我们也可以使用注解来指定成功响应:

@Operation(summary = "Gets customer by ID", description = "Customer must exist")
@ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "Ok", content = 
          { @Content(mediaType = "application/json", schema = 
            @Schema(implementation = CustomerResponse.class)) }),
        @ApiResponse(responseCode = "400", description = "Invalid ID supplied"), 
        @ApiResponse(responseCode = "404", description = "Customer not found"),
        @ApiResponse(responseCode = "500", description = "Internal server error", content = 
          { @Content(mediaType = "application/json", schema = 
            @Schema(implementation = ErrorResponse.class)) }) })
@GetMapping("/{id}")
public ResponseEntity<CustomerResponse> getCustomer(@PathVariable("id") Long id) {
    return ResponseEntity.ok(customerService.getById(id));
}

现在,让我们看看@ApiResponse中的一些属性。

4.1. responseCodedescription 属性

responseCodedescription属性都是@ApiResponse注解中的必需参数。重要的是,我们不能为具有相同代码属性的多个@ApiResponse定义。

message属性通常包含与响应关联的人可读消息:

@ApiResponse(responseCode = 400, message = "Invalid ID supplied")

4.2. content 属性

有时,端点使用不同的响应类型。例如,我们可以为成功响应和错误响应使用不同的类型。我们可以使用可选的content属性通过关联响应类作为模式来描述它们。

首先,我们定义一个在发生内部服务器错误时返回的类:

class ErrorResponse {

    private String error;
    private String message;

    // getters and setters
}

其次,为内部服务器错误添加一个新的@ApiResponse

@Operation(summary = "Gets customer by ID", description = "Customer must exist")
@ApiResponses(value = {
        @ApiResponse(responseCode = "400", description = "Invalid ID supplied"), 
        @ApiResponse(responseCode = "404", description = "Customer not found"),
        @ApiResponse(responseCode = "500", description = "Internal server error", 
          content = { @Content(mediaType = "application/json", 
          schema = @Schema(implementation = ErrorResponse.class)) }) })
@GetMapping("/{id}")
public ResponseEntity<CustomerResponse> getCustomer(@PathVariable("id") Long id) {
    return ResponseEntity.ok(customerService.getById(id));
}

5. @Operation@ApiResponse 的差异

总结一下,以下是@Operation@ApiResponse注解的主要差异:

@Operation

@ApiResponse

用于描述操作

用于描述操作可能的响应

用于成功响应

用于成功和错误响应

只能在方法级别定义

可以在方法或类级别定义

可以直接使用

只能在@ApiResponses注解内使用

6. 结论

在这篇文章中,我们了解了@Operation@ApiResponse注解的区别。

如往常一样,示例代码可在GitHub上找到:GitHub