AUTOMATE API DOCUMENTATION GENERATION USING JAVA SPRINGDOC AND SWAGGER UI
1. INTRODUCTION:
API Documentation is an important part of building REST APIs. In this article, I will see how to use Springdoc, a very convenient tool when automating API documentation generation based on OpenAPI 3 standards.
In this article, I will use the following technologies:
Java 8
Spring Boot 2: Spring Web MVC, Spring Data JPA
MySQL
Maven
Springdoc
2. AN API IS AVAILABLE
To get started, you can download the CRUD-ready Rest API source code at Github . Go to the file src/main/resources/application.propertiesto edit the username and password corresponding to your MySQL database. Create a testdb database in MySQL. Our application provided the following APIs for Book management:
Protocol Urls Act
POST /api/books create a new Book
GET /api/books get all the books
GET /api/books/:id get a Book with :id
PUT /api/books/:id Update a Book with :id
DELETE /api/books/:id delete a Book with :id
And the controller file like this:
@CrossOrigin
@RestController
@RequestMapping("/api/books")
public class BookController {
@Autowired
BookRepository bookRepository;
@PostMapping("/")
public ResponseEntity<Book> createBook(@RequestBody Book book) {
try {
Book _book = bookRepository
.save(new Book(book.getTitle(), book.getAuthor(), book.getDescription()));
return new ResponseEntity<>(_book, HttpStatus.CREATED);
} catch (Exception e) {
return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@GetMapping("/")
public ResponseEntity<List<Book>> getAllBooks() {
try {
List<Book> books = new ArrayList<Book>();
bookRepository.findAll().forEach(books::add);
if (books.isEmpty()) {
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<>(books, HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@GetMapping("/{id}")
public ResponseEntity<Book> getBookById(@PathVariable("id") long id) {
Optional<Book> bookData = bookRepository.findById(id);
if (bookData.isPresent()) {
return new ResponseEntity<>(bookData.get(), HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
@PutMapping("/{id}")
public ResponseEntity<Book> updateBook(@PathVariable("id") long id, @RequestBody Book book) {
Optional<Book> bookData = bookRepository.findById(id);
if (bookData.isPresent()) {
Book _book = bookData.get();
_book.setTitle(book.getTitle());
_book.setAuthor(book.getAuthor());
_book.setDescription(book.getDescription());
return new ResponseEntity<>(bookRepository.save(_book), HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
@DeleteMapping("/{id}")
public ResponseEntity<HttpStatus> deleteBook(@PathVariable("id") long id) {
try {
bookRepository.deleteById(id);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
} catch (Exception e) {
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
3. GET STARTED WITH SPRINGDOC-OPENAPI
It's very simple just add springdoc-openapi-ui dependency to pom.xml :
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.5.8</version>
</dependency>
When running the application, the OpenAPI json file will be available at /v3/api-docs
http://localhost:8080/v3/api-docs/
Swagger UI, our API documentation will be accessible at:
http://localhost:8080/swagger-ui/index.html?configUrl=/v3/api-docs/swagg...
Springdoc will scan for allowed packages and self-document the API according to Spring's structural standards. With the above BookController.java controller file, the Swagger UI will appear as follows:
We can see all the endpoints of the application and the Schema of the Book. When we open the endpoint view /api/book/{id} , we can see the HTTP Request and Response details:
Along with the fully usable Try It Out section:
4. CREATE DOCUMENTATION USING @OPERATION AND @APIRESPONSES
Next, we should better describe our API. Starting off, we can annotate the /api/book/{id} endpoint with @Operation and @ApiResponses
@Operation(summary = "Find book by ID", description = "Returns a single book", tags = { "book" })
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "successful operation", content = @Content(schema = @Schema(implementation = Book.class))),
@ApiResponse(responseCode = "400", description = "Invalid ID supplied", content = @Content),
@ApiResponse(responseCode = "404", description = "Book not found", content = @Content) })
@GetMapping("/{id}")
public ResponseEntity<Book> getBookById(@PathVariable("id") long id) {
Optional<Book> bookData = bookRepository.findById(id);
if (bookData.isPresent()) {
return new ResponseEntity<>(bookData.get(), HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
The effect is clearly visible:
And after adding annotations to all the endpoints we can have a clean, nice and easy to understand API Documentation page:
All source code you can find here .
5. JWT AUTHENTICATION WITH SPRINGDOC
@Operation there is another feature like security that can support endpoints that need authentication to be able to access. As an example jwt bearer token we can use:
@Operation(summary = "Get user by ID", description = "This can only be done by admin.",
security = { @SecurityRequirement(name = "bearer-key") },
tags = { "user" })
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "successful operation", content = @Content(schema = @Schema(implementation = User.class))),
@ApiResponse(responseCode = "400", description = "Invalid ID supplied", content = @Content),
@ApiResponse(responseCode = "404", description = "User not found", content = @Content) })
also add customOpenAPI to enable the Authenticate button:
@Bean
public OpenAPI customOpenAPI(@Value("1.5.8") String appVersion) {
var securitySchemeName = "bearer-key";
return new OpenAPI()
.components(new Components().addSecuritySchemes(securitySchemeName,
new SecurityScheme()
.name(securitySchemeName)
.type(SecurityScheme.Type.HTTP)
.scheme("bearer")
.bearerFormat("JWT")))
.info(new Info().title("Your API").version(appVersion)
.license(new License().name("Apache 2.0").url("http://springdoc.org")));
}
If you use SpringSecurity, make it possible to access Springdoc related URLs without user authentication.
class SecurityConfiguration(val jwtTokenProvider: JwtTokenProvider) : WebSecurityConfigurerAdapter() {
override fun configure(http: HttpSecurity) {
http
.authorizeRequests()
.antMatchers("/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html").permitAll()
.anyRequest().authenticated()
}
}