Fundamentos de la especificación OpenAPI

La especificación OpenAPI (OAS) es un formato estándar para describir API RESTful.

La especificación OpenAPI permite a los desarrolladores definir la estructura, parámetros, respuestas y otra información de la API de forma legible por máquina.

La especificación OpenAPI se conocía originalmente como especificación Swagger; posteriormente fue donada a OpenAPI Initiative y renombrada como OpenAPI.

Las funciones principales de la especificación OpenAPI incluyen:

  • Proporcionar documentación estandarizada para la API.
  • Soporte para pruebas automatizadas de la API.
  • Generar SDK de cliente.
  • Promover el desarrollo con separación de frontend y backend.

Actualmente, OpenAPI tiene dos versiones principales de uso generalizado:

  1. OpenAPI 2.0 (anteriormente Swagger 2.0)
  2. OpenAPI 3.x (última versión estable)

Se recomienda que los proyectos nuevos utilicen la versión 3.x de OpenAPI, ya que ofrece más funciones y mejoras.

Estructura de la especificación OpenAPI

Los documentos OpenAPI suelen escribirse en formato YAML o JSON.

A continuación se muestra una estructura básica de documento OpenAPI:

Ejemplo

openapi: 3.1.0 # Versión de OpenAPI
info:
title: API de ejemplo # Nombre de la API
description: Este es un documento de API de ejemplo
version: 1.0.0 # Versión de la API
servers:
- url: https://api.example.com/v1 # Dirección del servidor de la API
description: Entorno de producción
  - url: https://dev-api.example.com/v1
description: Entorno de desarrollo

paths: # Definición de rutas de la API
/users: # Ruta del endpoint
get: # Método HTTP
summary: Obtener todos los usuarios
description: Devuelve la lista de todos los usuarios del sistema
      operationId: getUsers
      tags:
- users # Etiqueta de agrupación
parameters: # Parámetros de solicitud
        - name: limit
          in: query
description: Límite en el número de resultados devueltos
          schema:
            type: integer
            default: 20
responses: # Definición de respuestas
'200': # Código de estado HTTP
description: Devuelve la lista de usuarios correctamente
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/User'
        '400':
description: Parámetros de solicitud incorrectos

components: # Componentes reutilizables
schemas: # Definición de modelos de datos
    User:
      type: object
      properties:
        id:
          type: integer
          format: int64
        name:
          type: string
        email:
          type: string
          format: email
      required:
        - id
        - name

Explicación detallada de los conceptos centrales de OpenAPI

1. Metadatos del documento (info)

La sección info contiene la información básica de la API, como título, descripción, versión, etc.:

Ejemplo

info:
title: API de gestión de usuarios
description: API para gestionar la información de los usuarios del sistema
  version: 1.0.0
  contact:
name: Equipo de soporte de la API
    email: [email protected]
  license:
    name: Apache 2.0
    url: https://www.apache.org/licenses/LICENSE-2.0.html

2. Información del servidor (servers)

La sección servers define la lista de servidores de API disponibles:

Ejemplo

servers:
  - url: https://api.example.com/v1
description: Entorno de producción
  - url: https://staging-api.example.com/v1
description: Entorno de pruebas

3. Rutas (paths)

La sección paths define todos los endpoints de la API y los métodos HTTP que soportan:

Ejemplo

paths:
  /users:
    get:
# Obtener lista de usuarios
    post:
# Crear nuevo usuario
  /users/{userId}:
    get:
# Obtener un usuario específico
    put:
# Actualizar usuario
    delete:
# Eliminar usuario

4. Operaciones (operations)

Cada método HTTP bajo una ruta define una operación de API:

Ejemplo

paths:
  /users/{userId}:
    get:
summary: Obtener detalles del usuario
description: Obtiene la información detallada del usuario según su ID
      operationId: getUserById
      tags:
        - users
      parameters:
        - name: userId
          in: path
          required: true
description: ID del usuario
          schema:
            type: integer
      responses:
        '200':
description: Información del usuario obtenida con éxito
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '404':
description: El usuario no existe
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

5. Parámetros (parameters)

Los parámetros se pueden definir en varias ubicaciones:

Ejemplo

parameters:
  - name: userId
in: path # Parámetro de ruta
    required: true
    schema:
      type: integer
  - name: filter
in: query # Parámetro de consulta
    schema:
      type: string
  - name: X-API-Key
in: header # Parámetro de cabecera
    schema:
      type: string
  - name: trace
in: cookie # Parámetro de cookie
    schema:
      type: string

6. Cuerpo de solicitud (requestBody)

Define el cuerpo de solicitud para métodos como POST, PUT, etc.:

Ejemplo

requestBody:
description: Datos del usuario
  required: true
  content:
    application/json:
      schema:
        $ref: '#/components/schemas/User'
    application/x-www-form-urlencoded:
      schema:
        $ref: '#/components/schemas/UserForm'

7. Respuestas (responses)

Define las posibles respuestas para cada operación:

Ejemplo

responses:
  '200':
description: Operación exitosa
    content:
      application/json:
        schema:
          $ref: '#/components/schemas/SuccessResponse'
  '400':
description: Error en los parámetros de solicitud
    content:
      application/json:
        schema:
          $ref: '#/components/schemas/ErrorResponse'

8. Componentes (components)

La sección components se utiliza para almacenar elementos reutilizables en todo el documento de la API:

Ejemplo

components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        email:
          type: string
          format: email
        roles:
          type: array
          items:
            type: string
            enum: [admin, user, editor]
      required:
        - name
        - email
   
    Error:
      type: object
      properties:
        code:
          type: integer
        message:
          type: string
      required:
        - code
        - message
 
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
   
    OAuth2:
      type: oauth2
      flows:
        implicit:
          authorizationUrl: https://example.com/oauth/authorize
          scopes:
read: Permiso de lectura
write: Permiso de escritura

9. Modelos de datos (schemas)

Define las estructuras de datos utilizadas en la API:

Ejemplo

schemas:
  Product:
    type: object
    properties:
      id:
        type: integer
      name:
        type: string
        maxLength: 100
      price:
        type: number
        format: float
        minimum: 0
      category:
        type: string
        enum: [electronics, books, clothing]

10. Seguridad (security)

Define los métodos de autenticación y autorización de la API:

Ejemplo

security:
  - ApiKeyAuth: []
  - OAuth2: [read, write]

Creación de un ejemplo completo de documento OpenAPI

A continuación se muestra un ejemplo más completo de una API de comercio electrónico:

Ejemplo

openapi: 3.1.0
info:
title: API de comercio electrónico
description: API para gestionar productos y pedidos de una tienda en línea
  version: 1.0.0
  contact:
name: Equipo de soporte de API
    email: [email protected]
    url: https://api.example.com/support
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT

servers:
  - url: https://api.example.com/v1
description: Entorno de producción
  - url: https://dev-api.example.com/v1
description: Entorno de desarrollo

tags:
  - name: products
description: Operaciones relacionadas con productos
  - name: orders
description: Operaciones relacionadas con pedidos
  - name: users
description: Operaciones relacionadas con usuarios

paths:
  /products:
    get:
summary: Obtener lista de productos
description: Devuelve la lista de todos los productos disponibles, con soporte para paginación y filtrado
      operationId: getProducts
      tags:
        - products
      parameters:
        - name: category
          in: query
description: Filtrar por categoría de producto
          schema:
            type: string
        - name: page
          in: query
description: Número de página
          schema:
            type: integer
            default: 1
        - name: limit
          in: query
description: Cantidad por página
          schema:
            type: integer
            default: 20
      responses:
        '200':
description: Lista de productos obtenida exitosamente
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                  products:
                    type: array
                    items:
                      $ref: '#/components/schemas/Product'
        '400':
description: Error de parámetros
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
   
    post:
summary: Crear nuevo producto
description: Crear información de un nuevo producto
      operationId: createProduct
      tags:
        - products
      security:
        - ApiKeyAuth: []
        - OAuth2: [write]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ProductCreate'
      responses:
        '201':
description: Producto creado exitosamente
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Product'
        '400':
description: Datos de solicitud no válidos
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
description: No autorizado
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /products/{productId}:
    get:
summary: Obtener detalles del producto
description: Obtener información detallada de un producto específico según su ID
      operationId: getProductById
      tags:
        - products
      parameters:
        - name: productId
          in: path
          required: true
description: ID del producto
          schema:
            type: integer
      responses:
        '200':
description: Información del producto obtenida exitosamente
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Product'
        '404':
description: El producto no existe
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
   
    put:
summary: Actualizar producto
description: Actualizar la información de un producto específico
      operationId: updateProduct
      tags:
        - products
      security:
        - ApiKeyAuth: []
        - OAuth2: [write]
      parameters:
        - name: productId
          in: path
          required: true
description: ID del producto
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ProductUpdate'
      responses:
        '200':
description: Producto actualizado exitosamente
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Product'
        '400':
description: Datos de solicitud no válidos
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
description: No autorizado
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
description: El producto no existe
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
   
    delete:
summary: Eliminar producto
description: Eliminar un producto específico
      operationId: deleteProduct
      tags:
        - products
      security:
        - ApiKeyAuth: []
        - OAuth2: [write]
      parameters:
        - name: productId
          in: path
          required: true
description: ID del producto
          schema:
            type: integer
      responses:
        '204':
description: Producto eliminado exitosamente
        '401':
description: No autorizado
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
description: El producto no existe
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /orders:
    get:
summary: Obtener lista de pedidos
description: Devuelve la lista de todos los pedidos, con soporte para paginación y filtrado
      operationId: getOrders
      tags:
        - orders
      security:
        - ApiKeyAuth: []
        - OAuth2: [read]
      parameters:
        - name: status
          in: query
description: Filtrar por estado del pedido
          schema:
            type: string
            enum: [pending, processing, shipped, delivered, cancelled]
        - name: page
          in: query
description: Número de página
          schema:
            type: integer
            default: 1
        - name: limit
          in: query
description: Cantidad por página
          schema:
            type: integer
            default: 20
      responses:
        '200':
description: Lista de pedidos obtenida exitosamente
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                  orders:
                    type: array
                    items:
                      $ref: '#/components/schemas/Order'
        '401':
description: No autorizado
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
   
    post:
summary: Crear nuevo pedido
description: Crear un nuevo pedido
      operationId: createOrder
      tags:
        - orders
      security:
        - ApiKeyAuth: []
        - OAuth2: [write]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OrderCreate'
      responses:
        '201':
description: Pedido creado exitosamente
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'
        '400':
description: Datos de solicitud no válidos
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
description: No autorizado
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

components:
  schemas:
    Product:
      type: object
      properties:
        id:
          type: integer
          format: int64
          readOnly: true
        name:
          type: string
          maxLength: 100
        description:
          type: string
        price:
          type: number
          format: float
          minimum: 0
        category:
          type: string
          enum: [electronics, books, clothing, food]
        inStock:
          type: boolean
          default: true
        createdAt:
          type: string
          format: date-time
          readOnly: true
        updatedAt:
          type: string
          format: date-time
          readOnly: true
      required:
        - name
        - price
        - category
   
    ProductCreate:
      type: object
      properties:
        name:
          type: string
          maxLength: 100
        description:
          type: string
        price:
          type: number
          format: float
          minimum: 0
        category:
          type: string
          enum: [electronics, books, clothing, food]
        inStock:
          type: boolean
          default: true
      required:
        - name
        - price
        - category
   
    ProductUpdate:
      type: object
      properties:
        name:
          type: string
          maxLength: 100
        description:
          type: string
        price:
          type: number
          format: float
          minimum: 0
        category:
          type: string
          enum: [electronics, books, clothing, food]
        inStock:
          type: boolean
   
    Order:
      type: object
      properties:
        id:
          type: integer
          format: int64
          readOnly: true
        userId:
          type: integer
          format: int64
        items:
          type: array
          items:
            $ref: '#/components/schemas/OrderItem'
        totalAmount:
          type: number
          format: float
          readOnly: true
        status:
          type: string
          enum: [pending, processing, shipped, delivered, cancelled]
          default: pending
        shippingAddress:
          $ref: '#/components/schemas/Address'
        createdAt:
          type: string
          format: date-time
          readOnly: true
        updatedAt:
          type: string
          format: date-time
          readOnly: true
      required:
        - userId
        - items
        - shippingAddress
   
    OrderCreate:
      type: object
      properties:
        userId:
          type: integer
          format: int64
        items:
          type: array
          items:
            $ref: '#/components/schemas/OrderItem'
        shippingAddress:
          $ref: '#/components/schemas/Address'
      required:
        - userId
        - items
        - shippingAddress
   
    OrderItem:
      type: object
      properties:
        productId:
          type: integer
          format: int64
        quantity:
          type: integer
          minimum: 1
          default: 1
        unitPrice:
          type: number
          format: float
          readOnly: true
      required:
        - productId
        - quantity
   
    Address:
      type: object
      properties:
        street:
          type: string
        city:
          type: string
        state:
          type: string
        zipCode:
          type: string
        country:
          type: string
      required:
        - street
        - city
        - state
        - zipCode
        - country
   
    Error:
      type: object
      properties:
        code:
          type: integer
        message:
          type: string
      required:
        - code
        - message
 
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
   
    OAuth2:
      type: oauth2
      flows:
        implicit:
          authorizationUrl: https://example.com/oauth/authorize
          scopes:
read: Permiso de lectura
write: Permiso de escritura

security:
  - ApiKeyAuth: []

Sintaxis básica de la especificación OpenAPI

La especificación OpenAPI admite dos formatos:

  1. YAML (recomendado)
  2. JSON

Ejemplo de formato YAML

Ejemplo

openapi: 3.0.0
info:
title: API de la tienda de mascotas
  version: 1.0.0
paths:
  /pets:
    get:
summary: Listar todas las mascotas
      responses:
        '200':
description: Lista de mascotas obtenida exitosamente

Ejemplo de formato JSON

Ejemplo

"openapi": "3.0.0",
  "info": {
    "title": "API de la tienda de mascotas",
    "version": "1.0.0"
  },
  "paths": {
    "/pets": {
      "get": {
        "summary": "Listar todas las mascotas",
        "responses": {
          "200": {
            "description": "Lista de mascotas obtenida exitosamente"
          }
        }
      }
    }
  }
}

Cómo utilizar la especificación OpenAPI

1. Crear y editar documentos OpenAPI

Puede crear y editar documentos OpenAPI utilizando las siguientes herramientas:

  • Swagger Editor: editor en línea, con vista previa y validación en tiempo real
  • Stoplight Studio: herramienta visual de diseño de API
  • VS Code + complemento OpenAPI: edición en el entorno de desarrollo integrado

2. Generación de documentos

La especificación OpenAPI permite generar automáticamente documentación de API atractiva. Las herramientas más utilizadas incluyen:

  • Swagger UI: generar documentación de API interactiva
  • ReDoc: proporciona documentación adaptable y personalizable
  • Slate: genera documentación estática elegante

3. Generación de código

OpenAPI puede generar automáticamente código de cliente y servidor en varios lenguajes:

  • OpenAPI Generator: admite 40+ lenguajes de programación
  • Swagger Codegen: genera código de cliente y servidor
  • NSwag: generador de código para el ecosistema .NET

4. Pruebas y simulación de API

La especificación OpenAPI también se puede utilizar para:

  • Pruebas automatizadas: utilizando herramientas como Postman, SoapUI, etc.
  • Simulación de API: Prism, Microcks, etc. pueden simular API basándose en la especificación OpenAPI

Mejores prácticas

1. Principios de diseño

  • Mantener una nomenclatura coherente en los endpoints
  • Utilizar métodos HTTP y códigos de estado adecuados
  • Diseñar una estructura de rutas URL clara

2. Recomendaciones para la documentación

  • Proporcionar descripciones y ejemplos detallados
  • Utilizar etiquetas para agrupar las API
  • Especificar claramente los parámetros requeridos

3. Estrategia de control de versiones

  • Incluir el número de versión en la URL (/v1/users)
  • Especificar la versión mediante la cabecera de solicitud (Accept: application/vnd.example.v1+json)
  • Indicar claramente la información de versión en el documento OpenAPI

Preguntas frecuentes

1. ¿Cuál es la diferencia entre OpenAPI y Swagger?

Swagger es el predecesor de la especificación OpenAPI. En 2016, la especificación Swagger fue donada a la Fundación Linux y renombrada como especificación OpenAPI. Ahora, "Swagger" suele referirse al conjunto de herramientas construido en torno a la especificación OpenAPI.

2. ¿Cuáles son las principales diferencias entre OpenAPI 2.0 y 3.x?

OpenAPI 3.x introdujo muchas funciones nuevas, incluyendo:

  • Reutilización mejorada de componentes
  • Definición más flexible del cuerpo de la solicitud
  • Definiciones de seguridad más sólidas
  • Soporte mejorado de JSON Schema
  • Soporte de links (enlaces) y callbacks (devoluciones de llamada)

3. ¿Cómo manejar la autenticación y autorización?

OpenAPI admite varios mecanismos de seguridad:

  • Claves de API
  • Autenticación básica HTTP
  • OAuth2.0
  • OpenID Connect
  • Autenticación mediante cabeceras personalizadas

Recursos de aprendizaje

  1. Documentación oficial:OpenAPI Initiative
  2. Herramientas:
  3. Recursos de aprendizaje:
Otras extensiones