====== 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.