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:
- OpenAPI 2.0 (anteriormente Swagger 2.0)
- 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
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
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
- 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
/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
/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
- 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
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
'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
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
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
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
- 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
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:
- YAML (recomendado)
- JSON
Ejemplo de formato YAML
Ejemplo
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
"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
- Documentación oficial:OpenAPI Initiative
- Herramientas:
- Recursos de aprendizaje: