Probar gratis
8 min lectura Guide 348 of 877

Mejores Prácticas de Diseño de APIs

Un buen diseño de API hace la vida de los consumidores más fácil y reduce la carga de soporte. Un mal diseño lleva a confusión, bugs y desarrolladores frustrados. Esta guía cubre enfoques prácticos de diseño de API que resisten la prueba del tiempo.

Principios de API

PRINCIPIOS FUNDAMENTALES:
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│ PRINCIPIO      │ DESCRIPCIÓN           │ BENEFICIO         │
│ ───────────────┼───────────────────────┼───────────────────│
│ Consistencia   │ Mismos patrones       │ Facilidad de      │
│                │ en todo               │ aprendizaje       │
│ ───────────────┼───────────────────────┼───────────────────│
│ Predecibilidad │ Comportamiento        │ Menos bugs        │
│                │ esperado              │                   │
│ ───────────────┼───────────────────────┼───────────────────│
│ Evolucionabilidad│ Cambiar de forma    │ Longevidad        │
│                │ segura                │                   │
│ ───────────────┼───────────────────────┼───────────────────│
│ Simplicidad    │ Fácil de usar        │ Adopción          │
└─────────────────────────────────────────────────────────────┘

Diseño RESTful

API Orientada a Recursos

DISEÑO DE API RESTFUL:
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│ RECURSOS (Piensa en sustantivos, no verbos):               │
│ ─────────────────────────────────────────────               │
│ ├── /users (NO /getUsers)                                  │
│ ├── /projects (NO /createProject)                          │
│ ├── /tasks (NO /deleteTask)                                │
│ ├── Recursos son COSAS                                     │
│ └── Métodos HTTP son ACCIONES                              │
│                                                             │
│ OPERACIONES CRUD:                                           │
│ ─────────────────                                           │
│ Método HTTP │ Operación │ Ejemplo                          │
│ ────────────┼───────────┼──────────────────────────────────│
│ GET         │ Leer      │ GET /users                       │
│ POST        │ Crear     │ POST /users                      │
│ PUT         │ Reemplazar│ PUT /users/123                   │
│ PATCH       │ Actualizar│ PATCH /users/123                 │
│ DELETE      │ Eliminar  │ DELETE /users/123                │
│                                                             │
│ JERARQUÍA DE RECURSOS:                                     │
│ ──────────────────────                                      │
│ Recursos anidados:                                         │
│ ├── GET /projects/123/tasks                                │
│ ├── POST /projects/123/tasks                               │
│ ├── GET /projects/123/tasks/456                            │
│ ├── Relaciones claras                                      │
│ └── Jerarquía lógica                                      │
│                                                             │
│ ESTRUCTURA DE URL:                                          │
│ ──────────────────                                          │
│ Nombrado consistente:                                      │
│ ├── Sustantivos en plural: /users, /tasks                 │
│ ├── Minúsculas: /user-profiles                            │
│ ├── Guiones para multi-palabra                            │
│ ├── Sin trailing slashes                                   │
│ ├── Sin extensiones de archivo                            │
│ └── Limpio, predecible                                    │
└─────────────────────────────────────────────────────────────┘

Request/Response

Formato de Datos

DISEÑO DE REQUEST/RESPONSE:
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│ JSON CONSISTENTE:                                           │
│ ─────────────────                                           │
│ Siempre la misma estructura:                               │
│                                                             │
│ Respuesta de éxito:                                        │
│ {                                                          │
│   "data": {                                                │
│     "id": 123,                                             │
│     "name": "Juan Pérez",                                 │
│     "email": "juan@ejemplo.com"                           │
│   }                                                        │
│ }                                                          │
│                                                             │
│ Respuesta de lista:                                        │
│ {                                                          │
│   "data": [                                                │
│     { "id": 123, "name": "Juan" },                        │
│     { "id": 124, "name": "María" }                       │
│   ],                                                       │
│   "meta": {                                                │
│     "total": 100,                                          │
│     "page": 1,                                             │
│     "perPage": 20                                          │
│   }                                                        │
│ }                                                          │
│                                                             │
│ CONVENCIONES DE NOMBRADO:                                   │
│ ──────────────────────────                                  │
│ Casing consistente:                                        │
│ ├── camelCase para JSON: firstName                        │
│ ├── snake_case también común: first_name                  │
│ ├── Elige uno, usa en todas partes                        │
│ ├── Coincide con convenciones de tu lenguaje              │
│ └── La consistencia es lo que más importa                │
│                                                             │
│ FILTRADO DE CAMPOS:                                         │
│ ───────────────────                                         │
│ Permite a clientes solicitar campos:                       │
│ ├── GET /users?fields=id,name,email                       │
│ ├── Reduce sobre-fetching                                  │
│ ├── Mejor performance                                      │
│ ├── Enfoque GraphQL para REST                             │
│ └── Opcional pero útil                                    │
└─────────────────────────────────────────────────────────────┘

Códigos de Estado HTTP

Uso Correcto

CÓDIGOS DE ESTADO HTTP:
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│ ÉXITO (2xx):                                               │
│ ─────────────                                               │
│ 200 OK          → GET/PUT/PATCH exitoso                   │
│ 201 Created     → POST exitoso (recurso creado)           │
│ 204 No Content  → DELETE exitoso (sin body)               │
│                                                             │
│ ERRORES DEL CLIENTE (4xx):                                 │
│ ───────────────────────────                                 │
│ 400 Bad Request → Input inválido (formato, sintaxis)     │
│ 401 Unauthorized→ Sin autenticación                       │
│ 403 Forbidden   → Sin permiso (autenticado pero sin acceso)│
│ 404 Not Found   → Recurso no existe                       │
│ 409 Conflict    → Duplicado/conflicto                     │
│ 422 Unprocessable→ Validación falló (semánticamente mal) │
│ 429 Too Many    → Rate limit excedido                     │
│                                                             │
│ ERRORES DEL SERVIDOR (5xx):                                │
│ ────────────────────────────                                │
│ 500 Server Error→ Error nuestro (culpa del servidor)     │
│ 502 Bad Gateway → Servicio upstream falló                │
│ 503 Unavailable → Servicio temporalmente no disponible   │
│                                                             │
│ ERRORES COMUNES:                                            │
│ ────────────────                                            │
│ ❌ 200 para errores (con mensaje de error en body)        │
│ ❌ 500 para errores de validación                         │
│ ❌ 404 cuando debería ser 403                              │
│ ✅ Usar código específico para cada situación            │
└─────────────────────────────────────────────────────────────┘

Manejo de Errores

Respuestas de Error

FORMATO DE RESPUESTA DE ERROR:
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│ ESTRUCTURA RECOMENDADA:                                     │
│ ────────────────────────                                    │
│ {                                                          │
│   "error": {                                               │
│     "code": "VALIDATION_ERROR",                           │
│     "message": "Los datos proporcionados son inválidos", │
│     "details": [                                           │
│       {                                                    │
│         "field": "email",                                 │
│         "message": "Formato de email inválido"           │
│       },                                                   │
│       {                                                    │
│         "field": "name",                                  │
│         "message": "El nombre es requerido"              │
│       }                                                    │
│     ],                                                     │
│     "requestId": "req_abc123"                             │
│   }                                                        │
│ }                                                          │
│                                                             │
│ COMPONENTES:                                                │
│ ─────────────                                               │
│ code    → Identificador único del tipo de error           │
│ message → Mensaje legible para humanos                    │
│ details → Errores específicos por campo (si aplica)      │
│ requestId → Para debugging/soporte                        │
│                                                             │
│ MENSAJES DE ERROR:                                          │
│ ──────────────────                                          │
│ ❌ "Error"                                                 │
│ ❌ "Something went wrong"                                  │
│ ✅ "El email 'abc' no tiene formato válido"             │
│ ✅ "No tienes permiso para eliminar este proyecto"       │
│                                                             │
│ Mensajes claros, específicos y accionables                │
└─────────────────────────────────────────────────────────────┘

Versionado

Estrategias de Versión

ESTRATEGIAS DE VERSIONADO DE API:
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│ OPCIÓN 1: VERSIONADO EN URL (Recomendado)                  │
│ ──────────────────────────────────────────                  │
│ /api/v1/users                                              │
│ /api/v2/users                                              │
│                                                             │
│ ✅ Más explícito y visible                                │
│ ✅ Fácil de cachear                                       │
│ ✅ Claro en logs y debugging                              │
│ ❌ Múltiples URLs para mismo recurso                      │
│                                                             │
│ OPCIÓN 2: VERSIONADO EN HEADER                             │
│ ──────────────────────────────                              │
│ Accept: application/vnd.api+json;version=1                │
│                                                             │
│ ✅ URL limpia                                              │
│ ❌ Menos visible                                           │
│ ❌ Más difícil de probar                                  │
│                                                             │
│ OPCIÓN 3: QUERY PARAMETER                                   │
│ ──────────────────────────                                  │
│ /api/users?version=1                                       │
│                                                             │
│ ✅ Simple                                                  │
│ ❌ Puede confundirse con otros params                     │
│                                                             │
│ CUÁNDO INCREMENTAR VERSIÓN:                                │
│ ────────────────────────────                                │
│ v1 → v2 cuando:                                           │
│ • Cambio en estructura de response                        │
│ • Campos removidos o renombrados                          │
│ • Cambio en comportamiento de endpoint                    │
│ • Cualquier cambio que rompa clientes                     │
│                                                             │
│ NO necesita nueva versión:                                 │
│ • Agregar campos opcionales                               │
│ • Nuevo endpoint                                           │
│ • Corrección de bugs                                      │
└─────────────────────────────────────────────────────────────┘

Paginación

Patrones de Paginación

PAGINACIÓN DE API:
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│ OFFSET-BASED (Más común):                                  │
│ ──────────────────────────                                  │
│ GET /users?page=2&perPage=20                              │
│                                                             │
│ Response:                                                   │
│ {                                                          │
│   "data": [...],                                           │
│   "meta": {                                                │
│     "total": 150,                                          │
│     "page": 2,                                             │
│     "perPage": 20,                                         │
│     "totalPages": 8                                        │
│   }                                                        │
│ }                                                          │
│                                                             │
│ ✅ Simple de implementar                                   │
│ ❌ Puede perder/duplicar ítems si datos cambian          │
│                                                             │
│ CURSOR-BASED (Más robusto):                               │
│ ───────────────────────────                                 │
│ GET /users?cursor=eyJpZCI6MTIzfQ==&limit=20              │
│                                                             │
│ Response:                                                   │
│ {                                                          │
│   "data": [...],                                           │
│   "cursors": {                                             │
│     "next": "eyJpZCI6MTQzfQ==",                          │
│     "prev": "eyJpZCI6MTAzfQ=="                           │
│   }                                                        │
│ }                                                          │
│                                                             │
│ ✅ Consistente incluso si datos cambian                   │
│ ✅ Mejor para feeds/timelines                             │
│ ❌ No puede saltar a página específica                   │
└─────────────────────────────────────────────────────────────┘

Soluciones Relacionadas