Course – LS – NPI (cat=Spring)
announcement - icon

Get started with Spring and Spring Boot, through the reference Learn Spring course:

>> LEARN SPRING
Course – LS (cat=REST) (INACTIVE)

Get started with Spring and Spring Boot, through the reference Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

In this tutorial, we’ll discuss the main differences between Swagger’s @Operation and @ApiResponse annotations.

2. Descriptive Documentation With Swagger

When we create a REST API, it’s also important to create its proper specification. Additionally, such a specification should be readable, understandable, and provide all essential information.

Moreover, the documentation should describe every change made to the API. It’d be exhausting and, more importantly, time-consuming to create REST API documentation manually. Fortunately, tools like Swagger can help us with this process.

Swagger represents a set of open-source tools built around OpenAPI Specifications. It can help us design, build, document, and consume REST APIs.

The Swagger Specification is a standard for documenting REST APIs. Using Swagger Specification, we can describe our entire API, such as exposed endpoints, operations, parameters, authentication methods, etc.

Swagger provides various annotations that can help us document REST API. Moreover, it provides the @Operation and @ApiResponse annotations to document responses for our REST API. In the remainder of this tutorial, we’ll use the below controller class and see how to use these annotations:

@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

The @Operation annotation is used to describe a single operation. An operation is a unique combination of a path and an HTTP method.

Additionally, using @Operation, we can describe the result of a successful REST API call. In other words, we can use this annotation to specify the general return type.

Let’s add the annotation to our method:

@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));
}

Next, we’ll go through some of the most used properties within @Operation.

3.1. The summary Property

The required summary property contains the operation’s summary field. Simply put, it provides a short description of the operation. However, we should keep this parameter shorter than 120 characters.

Here’s how we define the summary property inside the @Operation annotation:

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

3.2. The description Property

Using description, we can provide more details about the operation. For instance, we can place a text describing the endpoint’s restrictions:

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

3.3.  The hidden Property

The hidden property represents whether or not this operation is hidden.

4. @ApiResponse

It’s a common practice to return errors using HTTP status codes. We can use the @ApiResponse annotation to describe the concrete possible response of an operation.

While the @Operation annotation describes an operation and a general return type, the @ApiResponse annotation describes the rest of the possible return codes.

Furthermore, the annotation can be applied at the method level as well as at the class level. Moreover, annotation on the class level will be parsed only if an @ApiResponse annotation with the same code is not already defined on the method level. In other words, the method annotations have precedence over class annotations.

We should use the @ApiResponse annotations within the @ApiResponses annotation whether we have one or multiple responses. If we use this annotation directly, it will not be parsed by Swagger.

Let’s define the @ApiResponses and @ApiResponse annotations on our method:

@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));
}

We can use the annotation to specify the success response as well:

@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));
}

Now, let’s go through some of the properties used within @ApiResponse.

4.1. The responseCode and description Properties

Both responseCode and description properties are required parameters in the @ApiResponse annotation. It’s important to mention we cannot define more than one @ApiResponse with the same code property.

The message property usually contains a human-readable message that goes along with the response:

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

4.2. The content Property

Sometimes, an endpoint uses different response types. For example, we can have one type for success response and another for error response. We can describe them using the optional content property by associating a response class as a schema.

Firstly, let’s define a class that will be returned in case of an internal server error:

class ErrorResponse {

    private String error;
    private String message;

    // getters and setters
}

Secondly, let’s add a new @ApiResponse for internal server errors:

@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. Differences Between @Operation and @ApiResponse

To sum up, the following table shows the main differences between the @Operation and @ApiResponse annotations:

@Operation @ApiResponse
Used for describing an operation Used for describing the possible response of an operation
Used for a successful response Used for successful and error responses
Can be defined only on the method level Can be defined on a method or class level
Can be used directly Can be used only within the @ApiResponses annotation

6. Conclusion

In this article, we learnt the differences between the @Operation and @ApiResponse annotations.

As always, the source code for the examples is available on GitHub.

Course – LS (cat=Spring)

Get started with Spring and Spring Boot, through the Learn Spring course:

>> THE COURSE
Course – LS (cat=REST)

Get started with Spring and Spring Boot, through the Learn Spring course :

>> CHECK OUT THE COURSE
res – REST (eBook) (cat=REST)
Comments are closed on this article!