====== 02 - API First ====== La **API** es el contrato entre una aplicación y quienes la consumen. Define operaciones, datos de entrada y salida y respuestas posibles. ===== 1. API First y Code First ===== ^ Enfoque ^ Punto de partida ^ Uso del contrato ^ | **API First** | Se diseña el contrato antes de implementar | Guía y permite acordar el trabajo de clientes y servidor | | **Code First** | Se implementa primero | El contrato se deriva después del código, por ejemplo, con anotaciones | **API First** hace explícitas las decisiones de interfaz y permite revisarlas antes de implementarlas. El contrato describe lo que necesita el cliente; no expone automáticamente los modelos internos. @startuml left to right direction rectangle "Diseñar contrato" as design rectangle "Revisar y acordar" as review rectangle "Implementar API" as implement rectangle "Comprobar contrato" as verify design --> review review --> implement implement --> verify @enduml ===== 2. OpenAPI y Swagger ===== **OpenAPI** es una especificación para describir APIs **HTTP** en **YAML** o **JSON**. Define rutas y operaciones, parámetros, esquemas de datos, respuestas y restricciones. **Swagger** es un conjunto de herramientas para trabajar con **OpenAPI**. Por ejemplo, **Swagger UI** presenta el contrato como documentación interactiva. Este fragmento define una solicitud y dos respuestas de una operación: paths: /orders: post: operationId: createOrder requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateOrderRequest' responses: '201': description: Order created '400': description: Invalid request ===== 3. Contrato e implementación en Spring ===== El contrato **HTTP** y el código que implementa sus operaciones son responsabilidades relacionadas, pero pueden mantenerse separados. En **Spring**, **springdoc-openapi** genera un documento **OpenAPI** y **Swagger UI** a partir de las anotaciones del código. Una opción es declarar rutas, parámetros y documentación en una interfaz **Java** como ''OrderHttpApi'', y dejar que ''OrderController'' implemente sus operaciones. El nombre indica que es el contrato HTTP, distinto de una API interna que un módulo pueda ofrecer a otros módulos: @Tag(name = "Orders") public interface OrderHttpApi { @Operation(summary = "Create an order") @ApiResponses({ @ApiResponse(responseCode = "201", description = "Order created"), @ApiResponse(responseCode = "400", description = "Invalid request") }) @PostMapping("/orders") ResponseEntity create( @Valid @RequestBody CreateOrderRequest request); } @RestController public class OrderController implements OrderHttpApi { @Override public ResponseEntity create(CreateOrderRequest request) { // Delegar la operación y producir la respuesta. } } Así se separan las declaraciones del contrato HTTP de la lógica del controlador y **springdoc-openapi** puede generar la documentación. La interfaz puede diseñarse antes de implementar el controlador y formar parte de un flujo API First, pero queda ligada al código Java; el documento generado no es una especificación independiente del código. Otra opción es mantener una especificación **OpenAPI** en un archivo, por ejemplo ''orders-api.yaml'', como fuente de diseño antes de implementar. Es útil para revisar el contrato con consumidores, trabajar en paralelo o generar artefactos. La implementación debe comprobarse contra esa especificación. ^ Fuente del contrato ^ Ventaja ^ Precaución ^ | Interfaz Java ''OrderHttpApi'' y anotaciones | Contrato y documentación junto a la interfaz HTTP; documentación generada desde Spring | Se define desde el código; los cambios requieren revisar el contrato resultante | | Archivo ''orders-api.yaml'' | Contrato independiente, revisable antes de implementar | Hay que comprobar que la implementación sigue la especificación | Elegir una fuente de verdad evita mantener dos contratos manuales que puedan divergir. En ambos enfoques, los **DTO** HTTP describen los datos públicos y se mapean a modelos internos; no se exponen directamente los modelos del dominio. ===== 4. Cambios y comprobaciones ===== Un cambio es **incompatible** si obliga a los consumidores a cambiar sus solicitudes o cómo interpretan las respuestas. Eliminar un campo, cambiar su tipo o alterar el significado de una respuesta puede romper clientes. Al revisar cambios, comprobar: * Que operaciones, datos y respuestas describen el comportamiento público. * Que restricciones y errores son claros para quien consume la API. * Que los cambios no rompen compatibilidad sin una transición acordada. Se puede validar la sintaxis **OpenAPI**, comparar versiones y comprobar solicitudes y respuestas de la implementación. Las pruebas **HTTP** de ''controller'' verifican el comportamiento integrado; abrir **Swagger UI** no demuestra por sí solo la conformidad. Si se usa un archivo OpenAPI como fuente, hay que comprobar que la implementación se ajusta a él. **OpenAPI** describe el contrato; **Swagger UI** ayuda a explorarlo. La documentación no sustituye el diseño, la revisión de compatibilidad ni las pruebas.