REST API with Java — Part 3
API documentation using Swagger

This is the third post of my REST API series, where I write about my impressions and experience with this architecture style using Java with Spring Boot.
The full series of articles are listed below:
- Part I: Project setup and API implementation with Spring Boot
- Part II: HATEOAS and Root Entry Point
- Part III: API documentation using Swagger
- Part IV: API Authentication and Authorization with Spring Security
The implementation of each article is available on GitHub in a specific branch, and the final implementation is on the main branch.
In this article we will add Swagger integration to our existing API to document our endpoints.
The code of this article is available on GitHub in branch ‘ch-03’.
Swagger
Swagger is an interface description language for describing REST APIs, and has indeed become the standard for defining RESTful APIs.
According to swagger.io:
The ability of APIs to describe their own structure is the root of all awesomeness in Swagger. By reading your API’s structure, we can automatically build beautiful and interactive API documentation. We can also automatically generate client libraries for your API in many languages and explore other possibilities like automated testing. Swagger does this by asking your API to return a YAML or JSON that contains a detailed description of your entire API. This file is essentially a resource listing of your API which adheres to OpenAPI Specification.
In my opinion, a good Swagger UI page is the best documentation to get into an API specs, and it is very important for DX (Developer Experience).
Implementation
From our API built on Part 2, we’ll add swagger integration to document our API endpoints and generate a json/yml file and a html interactive page.
First of all, let’s add two more dependencies in the pom.xml (springfox):
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>3.0.0</version>
</dependency>
The first library will allow the Controller methods to be annotated with Swagger annotations, to automatically generate the describing files. The second one will enable an UI page to view the generated documentation.
Next, we need to create a configuration class “SwaggerConfig” (the class name doesn’t matter, as long as it instantiates the Docket Bean):
@Configuration
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(getApiInfo())
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.ant("/api/**"))
.build()
.useDefaultResponseMessages(false);
}
private ApiInfo getApiInfo() {
return new ApiInfoBuilder()
.title("Books API")
.description("Books API demonstration")
.contact(new Contact("Contact Name", "www.domain.com", "contact@email.com"))
.version("1.0")
.build();
}
}
And now we can describe our Controller methods (endpoints) with proper annotations:
@RestController
@RequestMapping("/api/v1/books")
@AllArgsConstructor
public class BooksController {
@Operation( summary = "Find books", description = "Get registered books" )
@GetMapping
public ResponseEntity<List<BookResponse>> getBooks() {
// implementation omitted
}
@Operation( summary = "Find book by id", description = "Find book by id",
responses = { @ApiResponse( responseCode = "404", description = "Book not found") }
)
@GetMapping("/{id}")
public ResponseEntity<BookResponse> getBook(@PathVariable("id") Integer id) {
// implementation omitted
}
@Operation( summary = "Register new book", description = "Register new book",
responses = { @ApiResponse( responseCode = "400", description = "Invalid Request data" ) }
)
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public ResponseEntity<BookResponse> createBook(@RequestBody @Valid BookRequest request) {
// implementation omitted
}
@Operation(
summary = "Update book info", description = "Update book info",
responses = {
@ApiResponse( responseCode = "400", description = "Invalid Request data" ),
@ApiResponse( responseCode = "404", description = "Book not found" )
}
)
@PutMapping("{id}")
public ResponseEntity<BookResponse> updateBook(@PathVariable("id") Integer id, @RequestBody @Valid BookRequest request) {
// implementation omitted
}
@Operation(
summary = "Delete book by id", description = "Delete book by id",
responses = { @ApiResponse( responseCode = "404", description = "Book not found") }
)
@DeleteMapping("{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public ResponseEntity deleteBook(@PathVariable("id") Integer id) {
// implementation omitted
}
@Operation( summary = "Find reviews", description = "Get review of a book" )
@GetMapping("{bookId}/reviews")
public ResponseEntity<List<ReviewResponse>> getReviews(@PathVariable("bookId") Integer bookId) {
// implementation omitted
}
@Operation(
summary = "Add new review", description = "Add new review to a book",
responses = {
@ApiResponse( responseCode = "400", description = "Invalid Request data" ),
@ApiResponse( responseCode = "404", description = "Book not found" )
}
)
@PostMapping("{bookId}/reviews")
@ResponseStatus(HttpStatus.CREATED)
public ResponseEntity<ReviewResponse> createReview(@PathVariable("bookId") Integer bookId, @RequestBody @Valid ReviewRequest request) {
// implementation omitted
}
}
And that’s it! We can run the application and by accessing the “http://localhost:9090/v2/api-docs”, we can see the generated json file.
To access the Swagger UI page the URL is “http://localhost:9090/swagger-ui/index.html”, where we can see all the operations available and its documentation

It’s even possible to test the operation by expanding its box and using the “Try it out” button:
