Audiencia
Esta guía es para desarrolladores que quieren diseñar APIs REST intuitivas, consistentes y mantenibles:
- Desarrolladores backend que construyen APIs desde cero y quieren seguir buenas prácticas
- Líderes técnicos que establecen estándares de diseño de APIs para sus equipos
- Desarrolladores frontend que quieren entender qué hace que una API esté bien diseñada
- Cualquiera que haya luchado con APIs inconsistentes y quiera hacerlo mejor
Deberías entender métodos HTTP y códigos de estado. Si no, empieza con HTTP para APIs REST.
Objetivo
Después de leer esta guía, serás capaz de:
- Diseñar URLs que sigan convenciones REST y sean intuitivas de usar
- Modelar recursos y sus relaciones correctamente
- Implementar paginación, filtrado y ordenación que escale
- Crear respuestas de error consistentes que ayuden a los desarrolladores a depurar
- Aplicar versionado básico para preparar tu API para el futuro
- Tomar decisiones de diseño informadas respaldadas por razonamiento claro
Esta guía construye habilidades prácticas—serás capaz de diseñar APIs reales después de leerla.
1. La Base: Pensamiento Orientado a Recursos
Antes de escribir código, necesitas cambiar tu mentalidad de “endpoints que hacen cosas” a “recursos que existen.”
Piensa en Sustantivos, No Verbos
El error más común en diseño de APIs es crear endpoints orientados a acciones:
# MAL: Orientado a acciones (estilo RPC)
POST /createUser
POST /getUserById
POST /updateUserEmail
POST /deleteUser
POST /sendPasswordReset
Estos endpoints son verbos. Describen qué haces, no qué existe. Este enfoque lleva a APIs inconsistentes e impredecibles.
En cambio, piensa en recursos—las “cosas” en tu sistema:
# BIEN: Orientado a recursos (estilo REST)
POST /users # Crear un usuario
GET /users/123 # Obtener usuario 123
PATCH /users/123 # Actualizar usuario 123
DELETE /users/123 # Eliminar usuario 123
POST /users/123/password-reset # Disparar reseteo de contraseña
Los métodos HTTP ya transmiten la acción. Tus URLs deben identificar qué está siendo afectado.
Identificando Recursos
Los recursos típicamente son:
- Entidades de negocio: Usuarios, productos, pedidos, facturas
- Relaciones: Membresías, amistades, suscripciones
- Acciones (cuando es necesario): Reseteos de contraseña, verificaciones de email
Pregúntate: “¿Cuáles son las cosas en mi sistema que tienen identidad y pueden ser manipuladas?”
graph TD
A[Tu Dominio] --> B[Entidades de Negocio]
A --> C[Relaciones]
A --> D[Acciones como Recursos]
B --> B1["users"]
B --> B2["products"]
B --> B3["orders"]
C --> C1["memberships"]
C --> C2["subscriptions"]
D --> D1["password-resets"]
D --> D2["email-verifications"]
style A fill:#e3f2fd
style B fill:#fff3e0
style C fill:#fff3e0
style D fill:#fff3e02. Diseño de URLs: El Arte de Nombrar
Las URLs son la interfaz de tu API. Deben ser predecibles, legibles y consistentes.
Usa Sustantivos en Plural
Las colecciones deben usar sustantivos en plural:
# BIEN: Sustantivos en plural
GET /users
GET /products
GET /orders
# MAL: Sustantivos en singular (inconsistente)
GET /user
GET /product
GET /order
Incluso para recursos singleton, considera el patrón de colección:
# Singleton en contexto de colección
GET /users/me # Usuario actual
GET /settings/current # Configuración actual
Jerarquía y Anidación
Los recursos frecuentemente tienen relaciones. Exprésalas a través de jerarquía de URLs:
# Pedidos de un usuario
GET /users/123/orders
# Pedido específico de un usuario
GET /users/123/orders/456
# Productos en un pedido
GET /users/123/orders/456/products
Pero no anides demasiado profundo. Más de 2-3 niveles se vuelve difícil de manejar:
# DEMASIADO PROFUNDO: Difícil de leer y usar
GET /companies/1/departments/2/teams/3/members/4/tasks/5
# MEJOR: Aplanar cuando sea posible
GET /tasks/5
GET /tasks?team_id=3
Regla general: Si un recurso tiene un identificador global, puede accederse directamente.
Convenciones de Nombres
| Convención | Ejemplo | Cuándo Usar |
|---|---|---|
| Minúsculas | /users, /products | Siempre |
| Guiones para múltiples palabras | /order-items, /password-resets | Siempre |
| Plural para colecciones | /users, /orders | Para colecciones |
| Sin barras finales | /users no /users/ | Siempre |
| Sin extensiones de archivo | /users no /users.json | Siempre |
| Sin verbos en URLs | /users no /getUsers | Siempre (usa métodos HTTP) |
Árbol de Decisiones para Diseño de URLs
flowchart TD
A[Diseñar nuevo endpoint] --> B{¿Es una colección
de cosas?}
B -->|Sí| C[Usa sustantivo plural:
/resources]
B -->|No| D{¿Es un ítem
específico?}
D -->|Sí| E[Usa colección + ID:
/resources/123]
D -->|No| F{¿Está anidado
bajo otro recurso?}
F -->|Sí| G{¿Profundidad > 2 niveles?}
F -->|No| H[Crear como nivel superior:
/resources]
G -->|Sí| I[Aplanarlo:
/child-resources?parent_id=X]
G -->|No| J[Anidarlo:
/parents/X/children]
style C fill:#c8e6c9
style E fill:#c8e6c9
style H fill:#c8e6c9
style I fill:#c8e6c9
style J fill:#c8e6c93. Colecciones e Ítems: Dos Patrones
Cada tipo de recurso típicamente expone dos patrones: la colección y el ítem.
Operaciones de Colección
Las colecciones representan grupos de recursos:
# Listar todos los usuarios (colección)
GET /users
→ Devuelve: Array de usuarios
# Crear un nuevo usuario (añadir a colección)
POST /users
→ Cuerpo: Datos del nuevo usuario
→ Devuelve: Usuario creado con ID
# Operaciones masivas (menos común)
DELETE /users?status=inactive
→ Elimina múltiples usuarios que coinciden con el criterio
Operaciones de Ítem
Los ítems representan recursos individuales:
# Obtener un usuario específico (ítem)
GET /users/123
→ Devuelve: Objeto de usuario único
# Actualizar un usuario específico (parcial)
PATCH /users/123
→ Cuerpo: Campos a actualizar
→ Devuelve: Usuario actualizado
# Reemplazar un usuario (completo)
PUT /users/123
→ Cuerpo: Objeto de usuario completo
→ Devuelve: Usuario reemplazado
# Eliminar un usuario específico
DELETE /users/123
→ Devuelve: 204 No Content
El Patrón CRUD Completo
| Operación | Método HTTP | URL | Cuerpo de Petición | Respuesta |
|---|---|---|---|---|
| Listar todos | GET | /users | - | Array de usuarios |
| Obtener uno | GET | /users/123 | - | Usuario único |
| Crear | POST | /users | Nuevo usuario | Usuario creado + cabecera Location |
| Actualizar parcial | PATCH | /users/123 | Campos cambiados | Usuario actualizado |
| Reemplazar completo | PUT | /users/123 | Usuario completo | Usuario reemplazado |
| Eliminar | DELETE | /users/123 | - | 204 No Content |
4. Paginación: Manejando Colecciones Grandes
Las colecciones del mundo real pueden tener millones de ítems. Necesitas paginación.
Tres Estrategias de Paginación
graph LR
A[Estrategias de Paginación] --> B[Basada en offset]
A --> C[Basada en cursor]
A --> D[Basada en keyset]
B --> B1["Simple, acceso aleatorio"]
B --> B2["Lenta en datasets grandes"]
C --> C1["Rápida, estable"]
C --> C2["Sin acceso aleatorio"]
D --> D1["Rápida, determinista"]
D --> D2["Requiere campo ordenable"]
style B fill:#fff9c4
style C fill:#c8e6c9
style D fill:#c8e6c9Paginación Basada en Offset
El enfoque más simple. Especifica offset (saltar) y limit (tomar):
GET /users?offset=0&limit=20 # Página 1
GET /users?offset=20&limit=20 # Página 2
GET /users?offset=40&limit=20 # Página 3
Respuesta con metadatos de paginación:
{
"data": [
{"id": 1, "name": "Alice"},
{"id": 2, "name": "Bob"}
],
"pagination": {
"offset": 0,
"limit": 20,
"total": 1547
}
}
Pros:
- Simple de implementar
- Soporta acceso aleatorio (saltar a página 50)
- Fácil de entender
Contras:
- Lenta en datasets grandes (la base de datos debe contar las filas del offset)
- Resultados inconsistentes cuando los datos cambian entre peticiones
- El rendimiento degrada:
OFFSET 1000000es costoso
Usar cuando: Datasets pequeños (< 10,000 ítems), acceso aleatorio necesario.
Paginación Basada en Cursor
Usa un cursor opaco (marcador de posición codificado):
GET /users?limit=20
→ Devuelve: data + cursor
GET /users?limit=20&cursor=eyJpZCI6MjB9
→ Devuelve: siguiente página + nuevo cursor
Respuesta:
{
"data": [
{"id": 21, "name": "Carol"},
{"id": 22, "name": "Dave"}
],
"pagination": {
"cursor": "eyJpZCI6NDB9",
"has_more": true
}
}
Pros:
- Rápida en datasets grandes (sin contar offset)
- Resultados estables (no saltará/duplicará cuando los datos cambien)
- Funciona bien con datos en tiempo real
Contras:
- Sin acceso aleatorio (debe recorrerse secuencialmente)
- El cursor puede volverse inválido si el ítem referenciado se elimina
- Más complejo de implementar
Usar cuando: Datasets grandes, UIs de scroll infinito, feeds en tiempo real.
Paginación Basada en Keyset
Usa el último valor visto de un campo ordenado:
GET /users?limit=20&sort=created_at
→ Devuelve: usuarios ordenados por created_at
GET /users?limit=20&sort=created_at&after=2026-01-01T12:00:00Z
→ Devuelve: usuarios creados después de esa marca de tiempo
Respuesta:
{
"data": [
{"id": 45, "name": "Eve", "created_at": "2026-01-01T12:00:01Z"},
{"id": 46, "name": "Frank", "created_at": "2026-01-01T12:00:02Z"}
],
"pagination": {
"after": "2026-01-01T12:00:20Z",
"has_more": true
}
}
Pros:
- Muy rápida (usa índices de base de datos directamente)
- Resultados deterministas
- No requiere conteo
Contras:
- Requiere un campo único y ordenable
- Sin acceso aleatorio
- Complejo para ordenaciones multi-columna
Usar cuando: Datasets grandes ordenados por timestamp o ID.
Formato de Respuesta de Paginación
Siempre incluye metadatos de paginación:
{
"data": [...],
"pagination": {
"total": 1547,
"limit": 20,
"offset": 40,
"has_more": true,
"links": {
"self": "/users?offset=40&limit=20",
"first": "/users?offset=0&limit=20",
"prev": "/users?offset=20&limit=20",
"next": "/users?offset=60&limit=20",
"last": "/users?offset=1540&limit=20"
}
}
}
5. Filtrado: Encontrando Lo Que Necesitas
Las colecciones necesitan filtrado para ser útiles.
Sintaxis de Parámetros de Consulta
El enfoque más común usa parámetros de consulta:
# Filtros de igualdad simples
GET /users?status=active
GET /users?role=admin
GET /users?status=active&role=admin # Lógica AND
# Múltiples valores (lógica OR)
GET /users?status=active,inactive
GET /users?role=admin&role=editor # Parámetros múltiples
# Filtrado de campos anidados
GET /users?address.city=London
Operadores para Filtros Complejos
Para comparaciones más allá de la igualdad, usa sufijos de operador o sintaxis especial:
# Enfoque 1: Sufijos de operador
GET /products?price_gte=100 # price >= 100
GET /products?price_lte=500 # price <= 500
GET /products?created_at_gt=2026-01-01 # creado después de fecha
# Enfoque 2: Notación de corchetes
GET /products?price[gte]=100
GET /products?price[lte]=500
GET /products?created_at[gt]=2026-01-01
# Enfoque 3: Operadores especiales
GET /products?filter=price:gte:100
GET /products?filter=price:between:100,500
Operadores de Filtro Comunes
| Operador | Significado | Ejemplo |
|---|---|---|
eq (por defecto) | Igual | ?status=active |
ne | No igual | ?status_ne=deleted |
gt | Mayor que | ?price_gt=100 |
gte | Mayor o igual que | ?price_gte=100 |
lt | Menor que | ?price_lt=500 |
lte | Menor o igual que | ?price_lte=500 |
in | En lista | ?status_in=active,pending |
contains | Cadena contiene | ?name_contains=john |
starts | Cadena empieza con | ?name_starts=john |
Búsqueda vs. Filtro
Distingue entre filtrado estructurado y búsqueda de texto completo:
# Filtro estructurado (coincidencia exacta de campo)
GET /products?category=electronics&brand=Sony
# Búsqueda de texto completo (busca en múltiples campos)
GET /products?q=wireless+headphones
GET /products?search=wireless+headphones
6. Ordenación: Ordenando Resultados
La ordenación controla el orden de los resultados de la colección.
Ordenación de Campo Único
# Ordenar por campo único
GET /users?sort=name # Ascendente (por defecto)
GET /users?sort=name:asc # Ascendente explícito
GET /users?sort=name:desc # Descendente
GET /users?sort=-name # Notación de prefijo: - significa desc
Ordenación Multi-Campo
# Múltiples campos de ordenación (separados por coma)
GET /users?sort=role:asc,name:asc
GET /users?sort=role,-created_at # role asc, luego created_at desc
Cabeceras de Respuesta de Ordenación
Incluye info de ordenación en la respuesta:
{
"data": [...],
"sorting": {
"fields": [
{"field": "role", "direction": "asc"},
{"field": "created_at", "direction": "desc"}
]
}
}
Ordenación por Defecto
Siempre define un orden por defecto para consistencia:
# Si no se especifica ordenación
GET /users
→ Por defecto: sort=created_at:desc (más recientes primero)
# O: sort=id:asc (orden estable)
7. Respuestas de Error: Ayudando a Desarrolladores a Depurar
Las buenas respuestas de error hacen tu API más fácil de integrar.
Estructura de Error Consistente
Cada respuesta de error debe seguir la misma estructura:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "La petición contiene campos inválidos",
"details": [
{
"field": "email",
"code": "INVALID_FORMAT",
"message": "El email debe ser una dirección de correo válida"
},
{
"field": "age",
"code": "OUT_OF_RANGE",
"message": "La edad debe estar entre 18 y 120"
}
],
"request_id": "req_abc123xyz"
}
}
Campos de Respuesta de Error
| Campo | Propósito | Ejemplo |
|---|---|---|
code | Tipo de error legible por máquina | "VALIDATION_ERROR", "NOT_FOUND" |
message | Explicación legible por humanos | "Usuario no encontrado" |
details | Errores a nivel de campo (para validación) | Array de errores de campo |
request_id | Para depuración/soporte | "req_abc123xyz" |
documentation_url | Enlace a docs de ayuda (opcional) | "https://api.example.com/docs/errors/RATE_LIMITED" |
Categorías de Códigos de Error
Define un conjunto consistente de códigos de error:
# Autenticación/Autorización
AUTHENTICATION_REQUIRED → 401
INVALID_CREDENTIALS → 401
TOKEN_EXPIRED → 401
PERMISSION_DENIED → 403
# Errores de recurso
NOT_FOUND → 404
ALREADY_EXISTS → 409
CONFLICT → 409
# Errores de validación
VALIDATION_ERROR → 400
INVALID_FORMAT → 400
MISSING_FIELD → 400
OUT_OF_RANGE → 400
# Límite de tasa
RATE_LIMITED → 429
# Errores de servidor
INTERNAL_ERROR → 500
SERVICE_UNAVAILABLE → 503
Árbol de Decisiones de Error
flowchart TD
A[Error ocurrido] --> B{¿Problema de
autenticación?}
B -->|Sí| C{¿Token presente?}
B -->|No| D{¿El recurso
existe?}
C -->|No| E["401 + AUTHENTICATION_REQUIRED"]
C -->|Sí| F{¿Token válido?}
F -->|No| G["401 + INVALID_CREDENTIALS"]
F -->|Sí| H["403 + PERMISSION_DENIED"]
D -->|No| I["404 + NOT_FOUND"]
D -->|Sí| J{¿Petición
válida?}
J -->|No| K["400/422 + VALIDATION_ERROR"]
J -->|Sí| L{¿Violación de regla
de negocio?}
L -->|Sí| M["409 + CONFLICT o personalizado"]
L -->|No| N["500 + INTERNAL_ERROR"]
style E fill:#ffccbc
style G fill:#ffccbc
style H fill:#ffccbc
style I fill:#ffccbc
style K fill:#fff9c4
style M fill:#fff9c4
style N fill:#ffcdd2Ejemplo de Error de Validación
Para validación de formularios/entrada, proporciona errores detallados a nivel de campo:
POST /users
Content-Type: application/json
{
"name": "",
"email": "not-an-email",
"age": -5
}
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"code": "VALIDATION_ERROR",
"message": "El cuerpo de la petición contiene campos inválidos",
"details": [
{
"field": "name",
"code": "REQUIRED",
"message": "El nombre es requerido"
},
{
"field": "email",
"code": "INVALID_FORMAT",
"message": "El email debe ser una dirección de correo válida"
},
{
"field": "age",
"code": "OUT_OF_RANGE",
"message": "La edad debe ser un número positivo"
}
]
}
}
8. Selección de Campos: Respuestas Parciales
Permite a los clientes solicitar solo los campos que necesitan.
Conjuntos de Campos Dispersos
# Devolver solo campos específicos
GET /users/123?fields=id,name,email
# Respuesta
{
"id": 123,
"name": "Alice",
"email": "[email protected]"
}
# Comparar con respuesta completa
GET /users/123
{
"id": 123,
"name": "Alice",
"email": "[email protected]",
"phone": "+1-555-1234",
"address": {...},
"preferences": {...},
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-10T12:00:00Z"
}
Selección de Campos Anidados
Para recursos relacionados:
# Seleccionar campos en objetos anidados
GET /users/123?fields=id,name,address.city,address.country
# Respuesta
{
"id": 123,
"name": "Alice",
"address": {
"city": "London",
"country": "UK"
}
}
Beneficios de la Selección de Campos
- Reducción de ancho de banda: Envía solo lo necesario
- Respuestas más rápidas: Menos datos que serializar
- Amigable para móviles: Crítico para ancho de banda limitado
- Privacidad: No exponer campos que el cliente no necesita
9. Versionado de API: Planificando para el Cambio
Las APIs evolucionan. El versionado te ayuda a hacer cambios sin romper clientes existentes.
¿Por Qué Versionar?
Sin versionado:
graph LR
A[Cambio en API] --> B[Todos los Clientes Rotos]
B --> C[Usuarios Enfadados]
B --> D[Tickets de Soporte]
B --> E[Pérdida de Confianza]
style A fill:#ffccbc
style B fill:#ffcdd2Con versionado:
graph LR
A[API v2 Lanzada] --> B[v1 Sigue Funcionando]
A --> C[Clientes Migran
a Su Ritmo]
B --> D[Sin Cambios que Rompen]
C --> D
D --> E[Usuarios Felices]
style A fill:#c8e6c9
style D fill:#c8e6c9
style E fill:#c8e6c9Versionado en Ruta de URL (Recomendado)
El enfoque más simple y visible:
# Versión en ruta de URL
GET /v1/users
GET /v2/users
# URL completa
https://api.example.com/v1/users
https://api.example.com/v2/users
Pros:
- Altamente visible y explícito
- Fácil de probar y depurar
- Funciona con todas las herramientas HTTP
- Claro en la documentación
Contras:
- Cambia todas las URLs cuando la versión aumenta
- Puede llevar a duplicación de código
Esta es la opción por defecto para la mayoría de APIs. Empieza aquí.
Versionado en Cabecera (Alternativa)
Versión especificada en cabecera de petición:
GET /users
Accept: application/vnd.example.v1+json
GET /users
Accept: application/vnd.example.v2+json
O cabecera personalizada:
GET /users
X-API-Version: 1
GET /users
X-API-Version: 2
Pros:
- URLs limpias
- Misma URL para todas las versiones
- Sigue negociación de contenido HTTP
Contras:
- Menos visible (no está en la URL)
- Más difícil de probar en navegador
- Fácil olvidar la cabecera
Versionado en Parámetro de Consulta (No Recomendado)
GET /users?version=1
GET /users?version=2
Evita este enfoque. Mezcla versionado con semántica de consulta y puede causar problemas de caché.
Cuándo Crear una Nueva Versión
Crea una nueva versión para cambios que rompen:
- Eliminar un campo
- Renombrar un campo
- Cambiar el tipo de un campo
- Cambiar estado requerido/opcional
- Cambiar formato de respuesta de error
- Cambiar esquema de autenticación
Cambios que no rompen no requieren nueva versión:
- Añadir nuevos campos (aditivo)
- Añadir nuevos endpoints
- Añadir nuevos parámetros opcionales
- Añadir nuevos códigos de error
Ciclo de Vida de Versión
v1 (actual) → v2 (lanzada) → v1 (deprecada) → v1 (sunset)
↓
6-12 meses de aviso
↓
v1 eliminada
Siempre anuncia la deprecación con antelación (6-12 meses mínimo para APIs de producción).
10. Poniéndolo Todo Junto: Ejemplo de API de E-Commerce
Diseñemos una API de e-commerce completa siguiendo todos los principios.
Jerarquía de Recursos
graph TD
A[Raíz de API] --> B[/users]
A --> C[/products]
A --> D[/orders]
A --> E[/categories]
B --> B1[/users/:id]
B1 --> B2[/users/:id/orders]
B1 --> B3[/users/:id/addresses]
C --> C1[/products/:id]
C1 --> C2[/products/:id/reviews]
D --> D1[/orders/:id]
D1 --> D2[/orders/:id/items]
E --> E1[/categories/:id]
E1 --> E2[/categories/:id/products]
style A fill:#e3f2fdDiseño Completo de Endpoints
Usuarios:
GET /v1/users # Listar usuarios (admin)
POST /v1/users # Crear usuario (registro)
GET /v1/users/me # Obtener usuario actual
PATCH /v1/users/me # Actualizar usuario actual
GET /v1/users/:id # Obtener usuario por ID (admin)
GET /v1/users/:id/orders # Obtener pedidos del usuario
GET /v1/users/:id/addresses # Obtener direcciones del usuario
POST /v1/users/:id/addresses # Añadir dirección
Productos:
GET /v1/products # Listar productos
GET /v1/products/:id # Obtener producto
POST /v1/products # Crear producto (admin)
PATCH /v1/products/:id # Actualizar producto (admin)
DELETE /v1/products/:id # Eliminar producto (admin)
GET /v1/products/:id/reviews # Obtener reseñas del producto
POST /v1/products/:id/reviews # Añadir reseña
Pedidos:
GET /v1/orders # Listar pedidos (propios o admin)
POST /v1/orders # Crear pedido
GET /v1/orders/:id # Obtener pedido
PATCH /v1/orders/:id # Actualizar pedido (cambios de estado)
DELETE /v1/orders/:id # Cancelar pedido
GET /v1/orders/:id/items # Obtener ítems del pedido
Categorías:
GET /v1/categories # Listar categorías
GET /v1/categories/:id # Obtener categoría
GET /v1/categories/:id/products # Obtener productos en categoría
Ejemplo: Listar Productos con Filtros
GET /v1/products?category=electronics&price_gte=100&price_lte=500&sort=-rating&limit=20&offset=0
HTTP/1.1 200 OK
Content-Type: application/json
{
"data": [
{
"id": "prod_123",
"name": "Auriculares Inalámbricos",
"category": "electronics",
"price": 299.99,
"rating": 4.8,
"in_stock": true
},
{
"id": "prod_456",
"name": "Altavoz Bluetooth",
"category": "electronics",
"price": 149.99,
"rating": 4.6,
"in_stock": true
}
],
"pagination": {
"offset": 0,
"limit": 20,
"total": 156,
"has_more": true
},
"filters_applied": {
"category": "electronics",
"price_gte": 100,
"price_lte": 500
},
"sorting": {
"field": "rating",
"direction": "desc"
}
}
Ejemplo: Crear Pedido con Error
POST /v1/orders
Content-Type: application/json
Authorization: Bearer eyJhbG...
{
"items": [
{"product_id": "prod_123", "quantity": 0},
{"product_id": "prod_999", "quantity": 2}
],
"shipping_address_id": "addr_456"
}
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"code": "VALIDATION_ERROR",
"message": "No se pudo crear el pedido debido a errores de validación",
"details": [
{
"field": "items[0].quantity",
"code": "OUT_OF_RANGE",
"message": "La cantidad debe ser al menos 1"
},
{
"field": "items[1].product_id",
"code": "NOT_FOUND",
"message": "El producto 'prod_999' no existe"
}
],
"request_id": "req_xyz789"
}
}
Qué Sigue
Esta guía cubrió los fundamentos del diseño de APIs REST—suficiente para construir una API bien estructurada.
Para temas más profundos como:
- Evolución de API sin romper clientes
- Estrategias de versionado para APIs en vivo
- Patrones de migración para APIs existentes
- Compatibilidad hacia atrás a largo plazo
- Políticas de deprecación y sunset
Ve el próximo curso: Diseño de APIs REST que No Rompen.
Términos Relacionados del Vocabulario
Profundiza tu comprensión:
- Recurso - El bloque de construcción fundamental de las APIs REST
- Paginación - Estrategias para manejar colecciones grandes
- Filtrado - Reduciendo los resultados de la colección
- Ordenación - Ordenando los resultados de la colección
- Manejo de Errores - Comunicando fallos a los clientes
- Versionado de API - Evolucionando APIs sin romper clientes