Documenting Spring Boot 2.7.x APIs Using OpenAPI 3.0
REST APIs documentation is one of the most important steps to fully support our potential clients. For new projects or to help to migrate your current ones to use one of the latest Spring Boot versions, the recommended initial point is for you project should be the Spring Initializr.
After generating, downloading or updating your project, you should integrate it with the SpringDoc. Since this dependency provides the easiest and really straightforward way to generate OpenAPI 3 docs and UI:
Gradle
dependencies {
...
implementation ‘org.springdoc:springdoc-openapi-ui:1.6.12’
}
Maven
<dependencies>
(...)
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.6.12</version>
</dependency>
</dependencies>
By default, no further configuration is required, althouhg we can tweak the behaviour by adding the necessary properties, including the UI params, to our application.yml
Show me the code
First, in order to showcase Open API generation, we can build a pretty simple CRUD API with a BookResource and AuthorResource controllers:
@RestController
@RequestMapping("/api/v1")
@Slf4j
public class BookResource {
private final BookService bookService;
@Autowired
public BookResource(BookService bookService) {
this.bookService = bookService;
}
@GetMapping(path = "/books", produces = {"application/json"})
public ResponseEntity<List<BookDto>> list();
public ResponseEntity<BookDto> get(@PathVariable("id") Long bookId);
@PostMapping(path = "/books", consumes = {"application/json"})
public ResponseEntity<Void> create(@Valid @RequestBody BookDto bookDto);
}-------------------------------------------------------------------@RestController
@RequestMapping("/api/v1")
@Slf4j
public class AuthorResource {
private final AuthorService authorService;
@Autowired
public AuthorResource(AuthorService authorService) {
this.authorService = authorService;
}
public ResponseEntity<Void> create(@Valid @RequestBody AuthorDto authorData);
public ResponseEntity<Void> delete(@PathVariable("id") Long authorId);
}
During the implemention of the controllers, is time to document the endpoints, by adding the proper descriptions to each method, by using the proper annotations from Swagger, like the following snippet where we are decorating the create book endpoint as follows:
@Operation(summary = "Creates a new book")
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "Created book"),
@ApiResponse(responseCode = "400", description = "Bad request"),
@ApiResponse(responseCode = "500", description = "Server Error")
@PostMapping(path = "/books", consumes = {"application/json"})
public ResponseEntity<Void> create(@Valid @RequestBody BookDto bookDto)
The final result should be like the following yaml file (notice that we are generating json by default):
openapi: 3.0.1
paths:
/api/v1/books:
get: (...)
post: (...)
/api/v1/authors:
post: (...)
'/api/v1/books/{id}':
get: (...)
'/api/v1/authors/{id}':
delete: (...)
components:
schemas:
AuthorDto: (...)
BookDto: (...)
The code for this project example, could be found in this repository, and specifically on this commit you can see how to upgrade from an old spring boot 2.x app using swagger spring-fox project.
Results
At this point, we only need to start the app, and to do so the project includes Maven and Gradle support. Hence, you can proceed as you prefer, by executing the boot app directly or alternatively, the generated jar file:
Gradle
./gradlew bootRun./gradlew bootJar
java -jar build/libs/spring-boot-junit5-example-1.0-SNAPSHOT.jar
Maven
mvn spring-boot:runmvn clean install
java -jar target/spring-boot-junit5-1.0-SNAPSHOT.jar
To access the swagger file or directly to the generated UI:
open http://localhost:8080/v3/api-docsopen http://localhost:8080/swagger-ui.html
Conclusions
As you can see, this process is becoming easier every time, thanks to projects like SpringDoc and less configuration required on the Spring Boot framework.
Also, if you are more interested to provide support to swagger to another framework, there is hopefully a simple way to chieve the same result easily.
One of my favourite options is Micronaut, and you can take a look at how to support OpenAPI on Micronaut 2.x , since it is a great alternative thanks to its reflection-free AOT solution.