Documentar un API REST con Swagger y Spring Boot

La documentaci贸n de un API es casi tan importante como construirlos con buenas pr谩cticas, pues su finalidad es que terceros la utilicen, por tal motivo, documentarla correctamente puede representar el 茅xito o fracaso en su implementaci贸n dentro de los sistemas de terceros:

Codigo fuente: Antes que nada, puedes descargar todo el c贸digo fuente en: https://github.com/codminddev/blog-spring-boot-swagger

La documentaci贸n de un API es casi tan importante como construirlos con buenas pr谩cticas, pues su finalidad es que terceros la utilicen, por tal motivo, documentarla correctamente puede representar el 茅xito o fracaso en su implementaci贸n dentro de los sistemas de terceros:

Por suerte, Spring Boot cuenta con la librer铆a de Swagger que permite analizar todo el proyecto y auto documentar todos los servicios REST que encuentre de forma autom谩tica. De esta forma, nos ahorramos una gran cantidad de trabajo de documentaci贸n. Por ejemplo, veamos el siguiente servicio:

@RestController
public class UserController {
	
	private List<UserDTO> users = new ArrayList<>();
	
	public UserController() {
		users.add(new UserDTO(1L, "admin"));
		users.add(new UserDTO(2L, "supervisor"));
		users.add(new UserDTO(3L, "cajero"));
	}

	@GetMapping(value = "users")
	public ResponseEntity<List<UserDTO>> findAll(){
		return ResponseEntity.ok(users); 
	}
	
	
	@PutMapping(value = "users")
	public ResponseEntity<UserDTO> update(UserDTO request){
		UserDTO user = users.stream()
				.filter(currentUser -> currentUser.getId() == request.getId())
				.findFirst()
				.orElseThrow(() -> new RuntimeException("No existe el usuario"));
		user.setName(request.getName());
		return ResponseEntity.ok(user);
	}
	
	@PostMapping(value = "users")
	public ResponseEntity<UserDTO> create(UserDTO request){
		users.add(request);
		return ResponseEntity.ok(request);
	}
	
	@DeleteMapping(value = "users/{userId}")
	public ResponseEntity<?> delete( @PathVariable("userId") long userId ) {
		UserDTO user = users.stream()
		.filter(currentUser -> currentUser.getId() == userId)
		.findFirst()
		.orElseThrow(() -> new RuntimeException("No existe el usuario"));
		users.remove(user);
		return ResponseEntity.ok().build();
		
	}
}

Podr谩 observar el cl谩sico servicio CRUD de usuarios, donde tenemos un servicio para consultar todos los usuarios (GET), crear nuevos (POST), actualizarlos (PUT) y finalmente eliminarlos (DELETE).

Por suerte, Swagger es tan potente que puede aprovecharse del API de reflection para analizar la estructura de los m茅todos, sus anotaciones y los par谩metros de entrada y salida para auto documentar el API, tal como se puede ver en la siguiente imagen:

Instalaci贸n

Para lograr esto, es requerido solamente dos pasos, agregar las librer铆as de Swagger y crear un objeto de configuraci贸n llamado Docket, veamos c贸mo ser铆a:

Lo primero es agregar las siguientes librer铆as en el archivo pom.xml:

<dependency>
	<groupId>io.springfox</groupId>
	<artifactId>springfox-swagger2</artifactId>
	<version>2.9.2</version>
</dependency>

<dependency>
	<groupId>io.springfox</groupId>
	<artifactId>springfox-swagger-ui</artifactId>
	<version>2.9.2</version>
</dependency>

La primera (springfox-swagger2) es la m谩s importante, pues es que se encarga de analizar la estructura de nuestro proyecto y crear los metadatos para crear la auto documentaci贸n del API. La segunda (springfox-swagger-ui) es que se encarga de tomar los metadatos de la primera y crear una interfaz gr谩fica amigable con los usuarios.

Configuraci贸n

El segundo paso es crear el archivo Docket, mediante el cual le indicamos a Swagger que es lo que debe de tomar en cuanta al momento de crear la documentaci贸n. Para esto, debemos de crear una clase que este anotada con @Configuration y @EnableSwagger2 y tenga un m茅todo que cree el objeto Docket:

@Configuration
@EnableSwagger2
public class SwaggerConfig {

	@Bean
	public Docket apiDocket() {
		return new Docket(DocumentationType.SWAGGER_2)
				.select()
				.apis(RequestHandlerSelectors.basePackage("com.codmind.swaggerapi.controllers"))
				.paths(PathSelectors.any())
				.build()
				.apiInfo(getApiInfo())
				;
	}
	
	private ApiInfo getApiInfo() {
		return new ApiInfo(
				"Order Service API",
				"Order Service API Description",
				"1.0",
				"http://codmind.com/terms",
				new Contact("Codmind", "https://codmind.com", "apis@codmind.com"),
				"LICENSE",
				"LICENSE URL",
				Collections.emptyList()
				);
	}
}

Dentro del m茅todo apiDocket construimos el objeto Docket, en el cual le indicamos que tome todos los servicios que se encuentre en el paquete com.codmind.swaggerapi.controllers y los auto documente por nosotros.

Finalmente, en el m茅todo getApiInfo, creamos el objeto ApiInfo, el cual define los datos de la propiedad del API, como su nombre, correo de contacto, licencia, etc.

La ejecuci贸n

Si todo sali贸 bien y corremos la aplicaci贸n, veremos el siguiente log:

Podr谩s ver que nos ha generado un path llamado /v2/api-docs, por lo que si los accedemos en el navegador (http://localhost:8080/v2/api-docs) podremos ver los metadatos del API generado por la librer铆a springfox-swagger2:

Sin embargo, esta documentaci贸n no es para nada intuitiva, y es por ello que hemos instalado la librer铆a springfox-swagger-ui, la cual toma esta metadata y crea la URL: http://localhost:8080/swagger-ui.html, la cual se ve as铆:

En esta p谩gina podemos apreciar 3 secciones, la primera corresponde al objeto ApiInfo, que contiene nombre del API, licencia, datos de contacto, etc.

La segunda secci贸n corresponde a los servicios, agrupados por controlador. En este caso, podemos apreciar el UserController (user-controller) con las 4 operaciones CRUD que hemos definido.

Si quieres aprender a crear un API REST profesional con Swagger, te invito a mi curso Mastering API REST, donde aprenderemos las mejores pr谩cticas para crear un API REST.

Finalmente, tenemos la secci贸n de Models (modelos), la cual describe todos los objetos que utilizamos como request/response.

Probando el API

Finalmente, si expandimos cualquier servicio, por ejemplo, el m茅todo create (POST) y presionamos el bot贸n Try It Out, podremos probar el servicio all铆 mismo:

Nos desplegar谩 los campos esperados por el servicio y si damos click en la secci贸n Model, podr谩s ver la estructura de la respuesta esperada.

Conclusiones

Documentar solo este servicio, nos podr铆a tomar varias horas, ya que es necesario documentar su nombre, los par谩metros que recibe, los retorna y adem谩s, habr铆a que describir cada unos de los objetos que recibe y responde, para que los consumidores tengan claridad de la estructura de cada uno de estos, pero como hemos podido comprobar, mediante Swagger nos evitamos todo este trabajo.

Deja un comentario

Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *