Swagger / Java & Spring Boot

La programación, además de ser funcional, debe ser elegante, limpia y legible. A día de hoy están más de moda que nunca las APIs para crear servicios web o microservicios. Una de las características bien buscadas a lograr en una API es que sea legible y que la podamos probar para poder ver sus entradas y salidas.

Para este escenario cuando desarrollamos en Java el “estándar defacto” se llama Swagger, en el diccionario, cuando buscamos que significa esta palabra refiere a una persona que es admirada por su estilo, forma de ser y por la forma en que habla y actúa. En este artículo entonces hablaremos de como crear un API que sea “swagger”.

¿Qué haremos en este artículo?

Crearemos un proyecto sencillo que permitirá añadir y buscar personas, usaremos como modelo una Lista en Java para almacenar y buscar las personas. El objetivo lo centraremos en el API y en la configuración de Swagger para usarlo.

Usaremos Java con el marco de trabajo Spring Boot, pero swagger lo puedes usar desde otros lenguajes, ya que es, en sí una especificación.

Creando el proyecto

Para crear el proyecto yo en lo personal empleo Intell IJ y la integración que este posee con Spring Intitializr, si lo usas, crea un proyecto Spring Boot con el módulo web seleccionado, también puedes hacerlo directo en la página o siemplemente usando el POM que aparece debajo. Al mismo ya le he añadido las dependencias para swagger.

Una vez con las dependencias listas en el POM, vamos entonces a ver la estructura de nuestro proyecto ejemplo:

Paquetes

  • common: En este paquete crearemos la clase SwaggerConfig, la cual es a los objetivos de este artículo la más importante, puesto que nos permitirá configurar a Swagger para nuestro proyecto.
  • model: Definiremos un sencillo modelo para trabajar llamado Persona.
  • controller: Se implementa un controlador para nuestro ejemplo que añadirá personas a una lista y los buscará por edad.
  • web: Es aquí donde está el otro punto de atención, en este paquete crearemos PersonaAPI, donde estarán las funciones (endpoints REST) que swagger documentará.

Componentes de Swagger

  • swagger: Componente básico encargado de detectar las APIs creadas por nuestra aplicación, determina los JSON de entrada/salida así como ofrece la lógica para comunicarnos con el API.
  • swagger-ui: Es la interfaz que empleando el componente anterior facilita y documenta la interacción con nuestra API.

Código de interés

En nuestra aplicación, hemos creado en el paquete common la clase SwaggerConfig, en su interior la implementación:

@Configuration
@EnableSwagger2
public class SwaggerConfig {
 @Bean
 public Docket api() {
 return new Docket(DocumentationType.SWAGGER_2)
 .select()
 .apis(RequestHandlerSelectors.any())
 .paths(PathSelectors.any())
 .build()
 .apiInfo(this.apiInfo());
 }
private ApiInfo apiInfo() {
 return new ApiInfo(
 "REST API",
 "REST API de ejemplo para sacavix.com.",
 "v1.0",
 "Todos los derechos otorgados",
 new Contact("Yoandy Pérez Villazón", "https://blog.sacavix.com", "sacavix@gmail.com"),
 "Licencia del API", "http://www.fsf.org", Collections.emptyList());
 }
}

El método api(), es el método principal y el que le indica a swagger que todos (any, cualquiera) nuestros endpoint REST los “mapee” y documente construyendo la ayuda para ellos, además le indica que la Información general del api la lea desde el método apiInfo() que hemos implementado.

Con este código que hemos escrito ya es suficiente para documentar nuestra API.

El código que se muestra a continuación es el normal del controlador REST, no tiene nada de especial que tenga que ponerse para que se “autodocumente con Swagger”.

Clase Persona, del paquete /model

public class Persona {
private String nombre;
 private int edad;
public Persona() {
 }
public Persona(String nombre, int edad) {
 this.nombre = nombre;
 this.edad = edad;
 }
public String getNombre() {
 return nombre;
 }
public int getEdad() {
 return edad;
 }
}

Clase PersonaLista del paquete controller

@Component
public class PersonaLista {
private List<Persona> listaPersonas;
public PersonaLista() {
 listaPersonas = new ArrayList<>();
 }
public Persona adicionarPersona(Persona persona) throws Exception {
 int size = listaPersonas.size();
 this.listaPersonas.add(persona);
if (size + 1 == this.listaPersonas.size())
 return persona;
 else
 throw new Exception("La persona no fue añadida");
}
public List<Persona> buscarPersonasPorEdad(int edad)
 {
return this.listaPersonas.stream()
 .filter(persona -> edad == persona.getEdad())
 .collect(Collectors.toList());
 }
}

El controlador que posee nuestra API, llamada PersonaAPI del paquete web.

@RestController
public class PersonaAPI {
@Autowired
PersonaLista personaLista;
@RequestMapping(value = "/adicionarPersona", method = RequestMethod.POST)
public Persona crearPersona(@RequestBody Persona persona) {
try {
return this.personaLista.adicionarPersona(persona);
} catch (Exception e) {
return null;
}
}
@RequestMapping(value = "/buscarPersona", method = RequestMethod.GET)
public List<Persona> buscarPersonaPorEdad(@RequestParam Integer edad){
return this.personaLista.buscarPersonasPorEdad(edad.intValue());
}
}

Con el código anterior, swagger-ui nos crea una vista con la documentación del API, la misma es accesible desde http://localhost:8080/swagger-ui.html, se muestra como aparece debajo.

Si desglosamos buscarPersona por ejemplo:

Como puede verse swagger nos crea un sandbox para probar directamente nuestra API, algo que es un valor agregado muy valioso.

Agregando más documentación al API

Si queremos un API más especificada podemos añadir en nuestro controlador REST anotaciones para esto.

  • Para documentar la clase añadimos @Api encima de PersonaAPI
  • Para especificar la función del método y lo que devuelve lo podemos hacer con la anotación @ApiOperation
  • La especificación de códigos HTTP de respuesta lo hacemos con @ApiResponse

Estas tres anotaciones las podemos ver en la práctica aquí:

@RestController
@Api(value="personasapi", description="Operaciones sobre la clase Persona")
public class PersonaAPI {
@Autowired
 PersonaLista personaLista;
@ApiOperation(value = "Añadir una persona", response = Persona.class)
 @RequestMapping(value = "/adicionarPersona", method = RequestMethod.POST)
 public Persona crearPersona(@RequestBody Persona persona) {
 try {
 return this.personaLista.adicionarPersona(persona);
 } catch (Exception e) {
 return null;
 }
 }
@ApiOperation(value = "Ver una lista de personas por edad", response = Persona[].class)
@ApiResponses(value = {
 @ApiResponse(code = 200, message = "Personas obtenidas correctamente"),
 @ApiResponse(code = 401, message = "No estas autorizado para ver obtener personas"),
 @ApiResponse(code = 403, message = "Está tratando de acceder a una persona no permitida"),
 @ApiResponse(code = 404, message = "La persona de esa edad no fue encontrada")
 })
 @RequestMapping(value = "/buscarPersona", method = RequestMethod.GET)
 public List<Persona> buscarPersonaPorEdad(@RequestParam Integer edad){
 return this.personaLista.buscarPersonasPorEdad(edad.intValue());
 }
}

La creación de entidades clientes a partir de Swagger: swagger-codegen

Si Swagger de por si ya es bastante completo, existe swagger-codegen, una utilidad escrita en Java que es capaz de leer nuestra API con swagger y generar entidades clientes para mappear nuestra API y acelerar la creación de aplicaciones clientes que consumen nuestra API.

Con swagger-codegen podemos generar código para ActionScript, Ada, Apex, Bash, C# (.net 2.0, 4.0 or later), C++ (cpprest, Qt5, Tizen), Clojure, Dart, Elixir, Eiffel, Erlang, Go, Groovy, Haskell (http-client, Servant), Java (Jersey1.x, Jersey2.x, OkHttp, Retrofit1.x, Retrofit2.x, Feign, RestTemplate, RESTEasy, Vertx, Google API Client Library for Java), Kotlin, Lua, Node.js (ES5, ES6, AngularJS with Google Closure Compiler annotations) Objective-C, Perl, PHP, PowerShell, Python, R, Ruby, Rust, Scala (akka, http4s, swagger-async-httpclient), Swift (2.x, 3.x, 4.x), Typescript (Angular1.x, Angular2.x, Fetch, jQuery, Node).

El proceso es tan sencillo como descargar el JAR y ejecutar el comando generador con el lenguaje destino al que queremos generar.

wget http://central.maven.org/maven2/io/swagger/swagger-codegen-cli/2.2.3/swagger-codegen-cli-2.2.3.jar -O swagger-codegen-cli.jar

Para generar un cliente para nuestra API sería por ejemplo:

java -jar swagger-codegen-cli.jar generate -i http://localhost:8080/v2/api-docs -l php -o /home/usuario/api-cliente

Conclusiones

¿Crees que swagger es útil?, a partir de ahora no lo dudes más, cada vez que crees un API REST documentala bien, usa swagger, tiene implementaciones para otros lenguajes.

14 thoughts on “Swagger / Java & Spring Boot

  1. Hi, i think that i saw you visited my weblog thus i came
    to “return the favor”.I am trying to find things to enhance my website!I
    suppose its ok to use some of your ideas!!

    1. Hi, thanks for your comment, please no problem, if I can help you with something, just tell me.

Comments are closed.