Contrato de API

Standards Jan 9, 2026 YAML
contract api-design specification interface agreement

Definición

Un contrato de API es una especificación formal y legible por máquina que define con precisión cómo funciona una API. Describe cada endpoint, qué entradas acepta cada uno (esquemas de petición), qué salidas devuelve (esquemas de respuesta), requisitos de autenticación, códigos de error, límites de velocidad y garantías de comportamiento. Piensa en él como un contrato legal entre el proveedor de la API y el consumidor - especifica exactamente qué pueden esperar ambas partes de la interacción.

A diferencia de la documentación informal que podría describir una API en prosa, un contrato es inequívoco y ejecutable. Las herramientas pueden validar que las implementaciones realmente coinciden con el contrato, que el código cliente usa correctamente la API, y que los cambios en cualquier lado mantienen la compatibilidad hacia atrás. Los contratos habilitan el desarrollo paralelo - los equipos de backend implementan el contrato mientras los equipos de frontend codifican contra él simultáneamente, usando servidores mock que siguen el contrato.

En la práctica, los contratos de API típicamente se escriben como especificaciones OpenAPI, esquemas GraphQL, Protocol Buffers o formatos similares. El contrato se convierte en la fuente única de verdad - la documentación se genera desde él, los SDKs se generan desde él, las pruebas validan contra él, y los API gateways lo hacen cumplir.

Ejemplo

Comunicación entre Microservicios: Un servicio de pagos y un servicio de pedidos necesitan comunicarse. Antes de escribir código, los equipos definen un contrato: POST /payments acepta orderId (UUID), amount (número), currency (código de 3 letras), devuelve paymentId y status. Ambos equipos codifican según este contrato. Las pruebas de integración validan que las llamadas reales a la API coincidan con el contrato.

Integración con API de Terceros: Stripe publica su contrato de API como una especificación OpenAPI. Cuando integras pagos con Stripe, descargas su contrato, generas un SDK con tipos seguros desde él, y tu IDE autocompleta las llamadas a métodos con los parámetros correctos. Si Stripe cambia su contrato (cambio incompatible), tu generación de SDK falla, alertándote inmediatamente.

Desarrollo de Aplicación Móvil: Un equipo construyendo aplicaciones iOS y Android necesita una API backend. Backend define el contrato primero: GET /users/{id} devuelve un objeto User con campos específicos. Los equipos móviles inmediatamente comienzan a construir la UI usando el contrato para generar datos mock, sin esperar la implementación del backend.

Cumplimiento de SLA: Un contrato especifica que GET /products debe responder dentro de 200ms en el percentil 99, manejar 10,000 peticiones/segundo, y mantener 99.9% de uptime. Las herramientas de monitorización validan la API en vivo contra estos términos del contrato, activando alertas cuando ocurren violaciones del SLA.

Detección de Cambios Incompatibles: Un equipo quiere renombrar “userId” a “id” en las respuestas de la API. Las herramientas de prueba de contratos comparan el cambio propuesto contra el contrato existente y lo marcan como un cambio incompatible - los clientes existentes esperan userId. El equipo mantiene userId para compatibilidad hacia atrás o versiona la API apropiadamente.

Analogía

El Plano del Edificio: Antes de construir un edificio, los arquitectos crean planos detallados especificando las dimensiones de cada habitación, ubicación de puertas, enchufes eléctricos, conexiones de fontanería. Los contratistas de diferentes oficios (eléctrico, fontanería, carpintería) trabajan simultáneamente usando el plano como contrato. Los inspectores verifican que el trabajo coincida con el plano. Un contrato de API es lo mismo - es el plano que múltiples equipos siguen para asegurar que todo conecta correctamente.

El Menú del Restaurante: Un menú es un contrato entre restaurante y cliente. Especifica qué platos están disponibles (endpoints), qué hay en cada plato (esquemas de petición/respuesta), precios (límites de velocidad), y tiempo de preparación (SLAs). Los clientes ordenan basándose en el contrato del menú. Si la cocina cambia una receta significativamente sin actualizar el menú, los clientes que ordenaron basándose en el contrato antiguo se sorprenderán.

El Contrato de Alquiler: Al alquilar un apartamento, firmas un contrato especificando monto de renta, fecha de vencimiento, responsabilidades de mantenimiento, condiciones de terminación. Tanto propietario como inquilino saben exactamente qué se espera. Si el propietario repentinamente cambia la renta a mitad del contrato sin enmienda, está en incumplimiento. Los contratos de API funcionan de la misma manera - los cambios requieren negociación (versionado).

Ejemplo de Código


# Contrato de API como Especificación OpenAPI
openapi: 3.1.0
info:
  title: Order Management API
  version: 2.1.0
  description: |
    Contrato para sistema de procesamiento de pedidos.

    **Garantías SLA:**
    - Tiempo de respuesta: 200ms (p99)
    - Disponibilidad: 99.9%
    - Límite de velocidad: 1000 peticiones/min por cliente
  contact:
    name: Soporte API
    email: [email protected]

servers:
  - url: https://api.example.com/v2
    description: Servidor de producción

paths:
  /orders:
    post:
      summary: Crear un nuevo pedido
      description: |
        Crea un pedido y devuelve inmediatamente con estado "pending".
        El procesamiento del pedido ocurre de forma asíncrona.
      operationId: createOrder
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateOrderRequest'
      responses:
        '201':
          description: Pedido creado exitosamente
          headers:
            X-Request-ID:
              schema:
                type: string
                format: uuid
              description: Identificador único de petición para rastreo
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'
        '400':
          description: Datos de petición inválidos
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Límite de velocidad excedido
          headers:
            X-RateLimit-Limit:
              schema:
                type: integer
              description: Peticiones permitidas por minuto
            X-RateLimit-Remaining:
              schema:
                type: integer
              description: Peticiones restantes en ventana actual
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /orders/{orderId}:
    get:
      summary: Obtener pedido por ID
      operationId: getOrder
      parameters:
        - name: orderId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Pedido encontrado
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'
        '404':
          description: Pedido no encontrado
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

components:
  schemas:
    CreateOrderRequest:
      type: object
      required:
        - customerId
        - items
      properties:
        customerId:
          type: string
          format: uuid
          description: UUID del cliente que hace el pedido
        items:
          type: array
          minItems: 1
          maxItems: 100
          items:
            type: object
            required: [productId, quantity]
            properties:
              productId:
                type: string
                format: uuid
              quantity:
                type: integer
                minimum: 1
                maximum: 1000
        shippingAddress:
          $ref: '#/components/schemas/Address'

    Order:
      type: object
      required:
        - id
        - customerId
        - items
        - status
        - total
        - createdAt
      properties:
        id:
          type: string
          format: uuid
        customerId:
          type: string
          format: uuid
        items:
          type: array
          items:
            type: object
            required: [productId, quantity, price]
            properties:
              productId:
                type: string
                format: uuid
              quantity:
                type: integer
              price:
                type: number
                description: Precio por unidad en USD
        status:
          type: string
          enum:
            - pending
            - processing
            - shipped
            - delivered
            - cancelled
          description: Estado actual del pedido
        total:
          type: number
          description: Monto total del pedido en USD
        createdAt:
          type: string
          format: date-time
        shippingAddress:
          $ref: '#/components/schemas/Address'

    Address:
      type: object
      required:
        - street
        - city
        - postalCode
        - country
      properties:
        street:
          type: string
          maxLength: 200
        city:
          type: string
          maxLength: 100
        postalCode:
          type: string
          pattern: "^[0-9]{5}(-[0-9]{4})?$"
        country:
          type: string
          pattern: "^[A-Z]{2}$"
          description: Código de país ISO 3166-1 alpha-2

    Error:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: string
          description: Código de error legible por máquina
        message:
          type: string
          description: Mensaje de error legible por humano
        details:
          type: array
          items:
            type: object
            properties:
              field:
                type: string
              issue:
                type: string

  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

security:
  - BearerAuth: []

Diagrama

graph TB
    subgraph "Contrato de API"
        CONTRACT[Especificación OpenAPI]

        CONTRACT --> ENDPOINTS[Endpoints
Rutas y Métodos] CONTRACT --> REQ[Esquemas de Petición
Validación de Entrada] CONTRACT --> RESP[Esquemas de Respuesta
Formato de Salida] CONTRACT --> AUTH[Autenticación
Esquemas de Seguridad] CONTRACT --> SLA[Términos SLA
Rendimiento, Límites] end subgraph "Lado Proveedor" IMPL[Implementación] TESTS[Pruebas de Contrato] IMPL -.Valida Contra.-> CONTRACT TESTS -.Hace Cumplir.-> CONTRACT end subgraph "Lado Consumidor" SDK[SDK Generado] MOCK[Servidor Mock] CLIENT[Código Cliente] CONTRACT -.Genera.-> SDK CONTRACT -.Alimenta.-> MOCK SDK --> CLIENT end CONTRACT --> DOCS[Documentación
Auto-Generada] style CONTRACT fill:#90EE90 style IMPL fill:#87CEEB style SDK fill:#FFD700

Buenas Prácticas

  1. Desarrollo contract-first - Define el contrato antes de escribir código de implementación
  2. Versiona explícitamente - Usa versionado semántico en el contrato (1.0.0, 2.0.0)
  3. Prueba contra el contrato - Ejecuta pruebas de contrato asegurando que la implementación coincida con la especificación
  4. Genera SDKs desde el contrato - No codifiques clientes a mano, genéralos para mantenerse sincronizados
  5. Documenta SLAs en el contrato - Incluye garantías de rendimiento, límites de velocidad como metadata
  6. Usa el contrato para mocking - Genera servidores mock desde el contrato para desarrollo paralelo
  7. Detecta cambios incompatibles - Usa herramientas para comparar versiones del contrato y marcar cambios incompatibles
  8. Haz los contratos descubribles - Publica contratos en un registro central o catálogo de APIs

Errores Comunes

Sin contrato alguno: Construir APIs solo con documentación informal o archivos README. Esto lleva a discrepancias entre documentación e implementación.

Implementation-first: Escribir código primero, luego extraer un contrato desde él. Esto pierde el beneficio principal - los contratos habilitan desarrollo paralelo y discusiones de diseño antes de codificar.

Contratos obsoletos: Escribir un contrato una vez y luego dejarlo divergir a medida que la API evoluciona. Contrato e implementación deben mantenerse sincronizados.

Contratos incompletos: Solo documentar casos felices (respuestas 200) e ignorar casos de error, casos límite, límites de velocidad, detalles de autenticación.

No probar contra el contrato: Tratar el contrato solo como documentación, no como pruebas ejecutables. Las pruebas de contrato deberían ejecutarse en CI/CD.

Cambios incompatibles sin versionado: Modificar el contrato de formas incompatibles hacia atrás sin incrementar la versión mayor, rompiendo clientes existentes.

Contratos demasiado rígidos: Hacer contratos tan específicos que son difíciles de evolucionar. Balancea precisión con flexibilidad para adiciones no incompatibles.

Standards & RFCs

Standards & RFCs
1)- [OpenAPI 3](https://reference.apios.info/es/terms/openapi-3/).1.0 Specification
2)- JSON [Schema](https://reference.apios.info/es/terms/schema/) Draft 2020-12
3)- GraphQL Schema Definition Language
4)- Protocol Buffers (protobuf)

Términos Relacionados