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()

}

}

Catalog: