A la hora de diseñar un microservicio que va a ser consumido por otras aplicaciones, ya sean Front, otros Backends o incluso aplicaciones móviles, lo más habitual hoy en día es usar un API REST para realizar el intercambio de datos, usando JSON como formato.

Este sistema facilita mucho la integración entre sistemas, pero no debemos olvidarnos que detrás de un sistema existe una persona encargada de realizar dicha integración. Para facilitar la integración con un sistema que “habla” REST, existen diversos estándares: Swagger, RAML o JSONAPI, que proveen de una interfaz “human readable” para que los desarrolladores puedan implementar de forma más fácil y eficaz dichas integraciones.

En este post vamos a ver cómo documentar el API REST usando Java como lenguaje de programación, Spring (con su módulo SpringBoot para exponer el API) y SpringFox, una librería que ofrece tanto el documento de especificación Swagger como una interfaz web para entender (incluso probar) el API REST.

En primer lugar, iremos a la página de Spring Initializer para generar el esqueleto de nuestro microservicio con SpringBoot:

Seleccionamos la dependencia Web y haremos clic en Generate project para descargar el esqueleto, que importaremos como proyecto Maven en el IDE que usemos.

Una vez importado el proyecto, la estructura que tendremos será la siguiente:

He renombrado el fichero de propiedades a aplication.yml. Además, hemos reutilizado el controller, bean, service y repository, podéis ver cómo se hace en este post, y consultar y descargar las clases de este repositorio.

NOTA: La implementación del repository la he modificado para “mockear” los métodos y así no incorporar la dependencia de Mongo.

Una vez incorporados estos componentes, la estructura del proyecto sería:

A modo de recordatorio, el servicio expone dos operaciones REST:

El objetivo es contar con una documentación del API REST que cumpla la especificación 2.0 de Swagger, y además con una interfaz web amigable que nos permita entender y probar dicho API REST.

Para incluir SpringFox, lo primero que haremos será incluir las dependencias de SpringFox y del UI en nuestro pom de Maven:


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

Después, editaremos la clase de arranque del SpringBoot para incluir los siguientes elementos:

  1. La anotación @EnableSwagger2 en la cabecera de la clase:```
  2. java
  3. &amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;gt;
  4. @SpringBootApplication&amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;gt;
  5. @EnableSwagger2&amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;gt;
  6. public class SpringbootSpringfoxApplication {&amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;gt;
2. La inyección por dependencia de la clase **TypeResolver** de fasterxml:```
java
&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
@Autowired&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
private TypeResolver typeResolver;&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;

  1. La inyección por valor de la propiedad app.version definida en el fichero application.yml con el valor de la versión establecida en el pom:

- **Inyección**:
- ```
- java
- &amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- @Value("${app.version}")&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- private String appVersion;&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- 
- ```
- El método anotado con **@Bean** que devuelve un objeto Docket y que configura el API con Swagger: ```
- java
- &amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- @Bean&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- public Docket swaggerApi() {&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- return new Docket(DocumentationType.SWAGGER_2)&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- .select()&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- .apis(RequestHandlerSelectors&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- .basePackage("com.isolisduran.springboot.controller"))&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- .paths(PathSelectors.regex("/api/.*"))&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- .build()&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- .pathMapping("/")&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- .genericModelSubstitutes(ResponseEntity.class)&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- .alternateTypeRules(AlternateTypeRules.newRule(&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- typeResolver.resolve(DeferredResult.class,&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- typeResolver.resolve(ResponseEntity.class,WildcardType.class)),&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- typeResolver.resolve(WildcardType.class)))&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- .useDefaultResponseMessages(false)&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- .apiInfo(apiInfo());&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- }&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- 
- ```
- Aunque la configuración de Swagger con SpringFox permite muchas más opciones, hemos dejado las más básicas para entender su funcionamiento. Lo más relevante de este método es:
- · Establece qué paquete del proyecto contiene los controllers que se expondrán en el API:
- ```
- java
- &amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- basePackage("com.isolisduran.springboot.controller")&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- 
- ```
- · A su vez, solo expone los controllers que expongan el path indicado:
- ```
- java
- &amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- PathSelectors.regex("/api/.*")&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- 
- ```
- El método **apiInfo()** para documentar los datos básicos del API:```
- java
- &amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- private ApiInfo apiInfo() {&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- return new ApiInfo(&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- "API Title",&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- "API Description",&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- appVersion,&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- "urn:tos",&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- new Contact("Contact Name", "http://www.none.com", "test@test.com"),&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- "API License",&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- "http://www.api-license-url.com");&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- }&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- 
- ```
- Con estos simples cambios ya tendríamos una documentación básica de nuestro API REST. Para probarlo, compilamos con:
- ```
- console
- &amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- $ mvn clean package&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- 
- ```
- Y ejecutamos el jar resultante con:
- ```
- console
- &amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- $ java -jar target/springboot-springfox-0.0.1-SNAPSHOT.jar&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
- 
- ```
- Con este comando arrancaremos el servidor en el puerto 8080 en nuestro entorno local para poder probar SpringFox. Abrimos un navegador y accedemos a la url local **https://www.paradigmadigital.com/v2/api-docs**. Veremos el JSON de Swagger:

<article class="block block-image  -inside-grid "><a href="https://www.paradigmadigital.com/wp-content/uploads/2017/03/4.png"target=""><img src="https://www.paradigmadigital.com/assets/img/defaults/lazy-load.svg"
        data-src="https://www.paradigmadigital.com/wp-content/uploads/2017/03/4.png"
        data-srcset="https://www.paradigmadigital.com/wp-content/uploads/2017/03/4.png 1920w,https://www.paradigmadigital.com/wp-content/uploads/2017/03/4.png 1280w,https://www.paradigmadigital.com/wp-content/uploads/2017/03/4.png 910w,https://www.paradigmadigital.com/wp-content/uploads/2017/03/4.png 455w"
        class="lazy-img"  
                sizes="(max-width: 767px) 80vw, 75vw"
                alt="" title="undefined"/></a></article>


A su vez, si accedemos a swagger-ui veremos la interfaz web del API REST:

<article class="block block-image  -inside-grid "><a href="https://www.paradigmadigital.com/wp-content/uploads/2017/03/5.png"target=""><img src="https://www.paradigmadigital.com/assets/img/defaults/lazy-load.svg"
        data-src="https://www.paradigmadigital.com/wp-content/uploads/2017/03/5.png"
        data-srcset="https://www.paradigmadigital.com/wp-content/uploads/2017/03/5.png 1920w,https://www.paradigmadigital.com/wp-content/uploads/2017/03/5.png 1280w,https://www.paradigmadigital.com/wp-content/uploads/2017/03/5.png 910w,https://www.paradigmadigital.com/wp-content/uploads/2017/03/5.png 455w"
        class="lazy-img"  
                sizes="(max-width: 767px) 80vw, 75vw"
                alt="" title="undefined"/></a></article>


Con esto tendríamos documentada de forma básica nuestro API REST, pero SpringFox ofrece más opciones para documentar nuestro API:

<h3 class="block block-header h--h20-175-500 left  ">Documentación de Controllers:</h3>

SpringFox permite documentar los Controllers de Spring usando anotaciones:

1. En el método GET añadiremos lo marcado en negrita:```
2. java
3. &amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
4. @ApiOperation(value="Get a person by id", notes="Provides an operation to get a Person object by its identifier")&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
5. @ApiResponses(value={&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
6. @ApiResponse(code=200, message="OK", response=Person.class),&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
7. @ApiResponse(code=404, message="Not Found", response=String.class),&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
8. @ApiResponse(code=500, message="Internal Server Error", response=String.class)&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
9. })&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
10. @RequestMapping(method = RequestMethod.GET, value = "/person/{tiged}", produces = MediaType.APPLICATION_JSON_VALUE)&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
11. public @ResponseBody ResponseEntity&amp;amp;amp;amp;amp;lt;Person&amp;amp;amp;amp;amp;gt; getById(@ApiParam(value="Person identifier", required=true) @PathVariable int id) {&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
12. Person person = personService.getById(id);&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
13. return new ResponseEntity&amp;amp;amp;amp;amp;lt;&amp;amp;amp;amp;amp;gt;(person, HttpStatus.OK);&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;
14. }&amp;amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;amp;gt;







  1. En el método POST añadiremos igualmente lo marcado en negrita:```
    java
    &amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;gt;
    @ApiOperation(value="Create a new Person", notes="Provides an operation to create a new Person object and return its identifier")&amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;gt;
    @ApiResponses(value={&amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;gt;
    @ApiResponse(code=201, message="Created", response=String.class),&amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;gt;
    @ApiResponse(code=400, message="Bad Request", response=String.class),&amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;gt;
    @ApiResponse(code=500, message="Internal Server Error", response=String.class)&amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;gt;
    })&amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;gt;
    @RequestMapping(method = RequestMethod.POST, value = "/person", produces = MediaType.TEXT_PLAIN_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)&amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;gt;
    public @ResponseBody ResponseEntity&amp;amp;amp;amp;lt;String&amp;amp;amp;amp;gt; create(@ApiParam(value="JSON with Person to create", required=true) @Valid @RequestBody Person person) {&amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;gt;
    String newPersonId = String.valueOf(personService.create(person).getId());&amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;gt;
    return new ResponseEntity&amp;amp;amp;amp;lt;String&amp;amp;amp;amp;gt;(newPersonId, HttpStatus.CREATED);&amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;gt;
    }&amp;amp;amp;amp;lt;br /&amp;amp;amp;amp;gt;

**NOTA**: Las anotaciones anteriores son específicas de Swagger y son provistas por la dependencia que SpringFox tiene de Swagger.

<h3 class="block block-header h--h20-175-500 left  ">Documentación de Beans:</h3>

El la clase Person incluiremos las siguientes anotaciones:

```undefined
java
<br />
@ApiModelProperty(value="Person identifier", required=true, example="1", position=1)<br />
private int id;<br />
@ApiModelProperty(value="Person name", required=true, example="MyName", position=2)<br />
private String name;<br />
@ApiModelProperty(value="Person address", required=false, example="MyName", position=3)<br />
private String address;<br />

% block:blockquote
% items:
% text:NOTA: Al igual que en el caso del controller, las anotaciones anteriores son específicas de Swagger y son provistas por la dependencia que SpringFox tiene de Swagger.
% endblock

Una vez hemos incluido estas anotaciones, compilamos de nuevo el proyecto con mvn clean package, ejecutamos de nuevo con java -jar para arrancar y probar el servicio en nuestro entorno local, y recargamos la url local en nuestro navegador:

Documentación del Get:

Documentación del Post:

Como podemos observar, con las anotaciones incluidas, tenemos una documentación más rica, con descripciones de los atributos de métodos y objetos, explicación de cada operación y resultados esperados en caso de éxito y error.

Además, como podemos observar, podemos probar interactivamente las operaciones expuestas en el API:

Ejecución del Get:

Ejecución del Post:

SpringFox nos proporciona de forma muy amigable la posibilidad de documentar nuestra API REST sin tener que generar la documentación nosotros mismos a mano.

A la vez que escribimos el código podemos documentar también el API, con lo que siempre tendremos control sobre los cambios introducidos. Además, al incluir el UI, facilita también la integración y pruebas por parte de las aplicaciones consumidoras.

Podéis encontrar el código de ejemplo en el repositorio de GitHub de Paradigma.

Cuéntanos qué te parece.

Los comentarios serán moderados. Serán visibles si aportan un argumento constructivo. Si no estás de acuerdo con algún punto, por favor, muestra tus opiniones de manera educada.

Suscríbete

Estamos comprometidos.

Tecnología, personas e impacto positivo.