Implementar Api First con Java y Maven
Desde que comencé a desarrollar api’s siempre han estado presente 2 conceptos, api first y code first. De forma muy resumida se entiende que api first primero diseñas el api y después codificas, caso contrario a code first que comienzas a codificar primero.
Cada estilo tiene sus ventajas y desventajas, por ahora me enfocare en api first e intentaré explicarte todo lo que yo desconocía. Normalmente en un desarrollo diseñaba el api en la especificación de Open Api apoyándome de swagger editor y al terminar generaba el código directamente desde la página web y lo pegaba en mi proyecto.
Tiene algo de sentido, cumplía con el principio de api first pero qué sucede cuando el api necesita cambios ya sea editar algún endpoint existente o agregar nuevos. Te diré lo que yo hacía, ignoraba totalmente el api first y me pasaba a code first lo cual me parece más práctico, lo cierto es que si tu haces lo mismo sabras que funciona pero con la experiencia comienzas a notar que algo no anda bien o parece algo extraño esa forma de desarrollar.
Con el tiempo me di cuenta que solo estaba implementando una parte del api first que consiste en diseñar el api y la segunda parte que no hacía era apoyarme de alguna herramienta o librería para auto-generar el código de la especificación del api directamente en mi proyecto.
Open api generador
Después de conocer esta librería el enfoque Api First comienza a tener más sentido. Imagina que ya tienes diseñada un api y usas open api generator para auto-generar las clases pojo que representan las entradas y salidas del api además de las interfaces de los controladores, ahora únicamente implementas estas interfaces.
Con el tiempo te piden agregar nuevos endpoints y en lugar de hacerlo directamente en código tomás la especificación yaml del api y agregas los nuevos endpoints, ahora vuelves a utilizar directamente open api generator para autogenerar el código e implementar las nuevas interfaces generadas.
Ahora ¿Cómo comenzamos? En el siguiente repositorio implemente la clásica API de Pet Store que se encuentre como ejemplo en la página web de swagger editor. Lo importante no es el api en este momento si no cómo lo implementamos en clases java.
Las configuraciones de open api generator se realizan en el archivo POM haciendo uso del plugin openapi-generator-maven-plugin las siguientes configuraciones son las mínimas obligatorias.
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>7.12.0</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<!-- Ruta a tu archivo OpenAPI -->
<inputSpec>${project.basedir}/src/main/resources/api.yaml</inputSpec>
<!-- Generador de código Java usando Spring Boot -->
<generatorName>java</generatorName>
<!-- Elegimos Spring Boot como tipo de servidor -->
<generatorName>spring</generatorName>
<library>spring-boot</library>
<!-- Directorio donde se generará el código -->
<output>${project.build.directory}/generated-sources/openapi</output>
<!-- Paquete base para el código generado -->
<apiPackage>com.javyhuerta.petstore.api</apiPackage>
<modelPackage>com.javyhuerta.petstore.model</modelPackage>
<invokerPackage>com.javyhuerta.petstore.invoker</invokerPackage>
<configOptions>
<interfaceOnly>true</interfaceOnly>
<useSpringBoot3>true</useSpringBoot3>
<skipDefaultInterface>true</skipDefaultInterface>
</configOptions>
</configuration>
</execution>
</executions>
</plugin>
La mayoría de las configuraciones son autoexplicativas y solo para no dejar dudas me enfocaré en las que pueden generar alguna confusión.
| Propiedad | Descripció |
|---|---|
| apiPackage | Es el paquete donde se generarán las interfaces o controladores de los endpoints definidos en tu especificación OpenAPI. |
| modelPackage | Paquete donde se colocarán las clases modelo que representan los schemas del OpenAPI (como User, Order, Pet, etc.). |
| invokerPackage | Contiene clases utilitarias que gestionan cosas como: Inicialización,Serialización JSON, Configuración de errores, Validación, Cosas internas del cliente o servidor |
| interfaceOnly | Genera solo las interfaces de los controladores (sin controladores concretos). |
| skipDefaultInterface | Evita generar implementaciones por defecto (default) dentro de la interfaz. |
| useSpringBoot3 | Usa jakarta.* en lugar de javax.*, necesario para Spring Boot 3. |
Adicionalmente se requiere agregar la siguiente librería para el manejo de los valores Nullable ya que es utilizado por Open Api Generator para diferenciar entre un valor nulo y un valor no enviado.
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>jackson-databind-nullable</artifactId>
<version>0.2.6</version>
</dependency>
Utilizamos el siguiente comando para auto generar el código
mvn clean compile
Una vez terminado la ejecución del comando podremos ver el resultado dentro de la carpeta target
├── api.yaml
├── application.properties
└── com
└── javyhuerta
└── petstore
├── PetstoreApplication.class
├── api
│ ├── ApiUtil.class
│ ├── PetApi.class
│ ├── StoreApi.class
│ └── UserApi.class
└── model
├── Category.class
├── Error.class
├── ModelApiResponse.class
├── Order$StatusEnum.class
├── Order.class
├── Pet$StatusEnum.class
├── Pet.class
├── Tag.class
└── User.class
Por último implementamos alguna de las interfaces dentro de nuestro proyecto y será todo lo que debemos hacer.
@RestController
public class PetController implements PetApi{
// … Código java
}
¿Qué sigue?
Con este ejercicio podemos darnos cuenta cómo implementar la librería open api generator para auto generar código java a partir de la especificación del api, ahora cada que se necesite hacer un cambio podemos actualizar la especificación del api y volver a auto generar el código sin necesidad de estar pasando de api first a code first.
