Diseño de API
Elegir el Tipo de API Correcto
| Tipo | Mejor para | Evitar cuando |
|---|
| REST | APIs públicas, CRUD, clientes simples, IoT | Datos anidados complejos, iteración rápida de esquemas |
| GraphQL | Aplicaciones móviles, datos anidados complejos, múltiples clientes | CRUD simple, equipos pequeños nuevos en esto |
| tRPC | Monorepos de TypeScript, APIs internas full-stack en TypeScript | Clientes que no usan TypeScript, APIs públicas |
| gRPC | Comunicación de microservicios de alto rendimiento, streaming | Clientes de navegador, casos de uso simples |
Diseño de API REST
Convenciones de URL
GET /users ← listar
GET /users/{id} ← individual
POST /users ← crear
PUT /users/{id} ← reemplazar
PATCH /users/{id} ← actualización parcial
DELETE /users/{id} ← eliminar
# Recursos anidados
GET /users/{id}/orders
POST /users/{id}/orders
# Acciones (cuando los verbos REST no son suficientes)
POST /orders/{id}/cancel
POST /users/{id}/activate
Códigos de Estado HTTP
| Código | Usar cuando |
|---|
| 200 | GET, PUT, PATCH exitosos |
| 201 | POST exitoso que crea |
| 204 | DELETE exitoso (sin cuerpo) |
| 400 | Falla de validación, solicitud incorrecta |
| 401 | Autenticación faltante o inválida |
| 403 | Autenticado pero no autorizado |
| 404 | Recurso no encontrado |
| 409 | Conflicto (duplicado, desajuste de versión) |
| 422 | Entidad no procesable (errores semánticos) |
| 429 | Límite de tasa excedido |
| 500 | Error inesperado del servidor |
Envoltura de Respuesta
{
"data": [...],
"meta": { "total": 100, "page": 1, "perPage": 20 }
}
{ "data": { "id": "1", "name": "James" } }
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Error de validación",
"details": [{ "field": "email", "issue": "Formato inválido" }]
}
}
Principios de Diseño de API
Estrategia de Versionado
# Versionado por URL (más visible, más fácil de enrutar)
/v1/users
/v2/users
# Versionado por cabecera (URLs más limpias)
Accept: application/vnd.api+json;version=2
Nunca rompas clientes existentes. Depreca, luego elimina.
Paginación
# Offset (simple, bueno para conjuntos pequeños)
GET /posts?page=2&perPage=20
# Cursor (rápido para grandes conjuntos, usa para scroll infinito)
GET /posts?cursor=eyJpZCI6MTAwfQ&limit=20
Filtrado y Ordenamiento
GET /orders?status=pending&userId=123
GET /products?sort=-price,name # prefijo - = descendente
GET /products?fields=id,name,price # conjuntos de campos dispersos
Idempotencia
# Incluye clave de idempotencia para operaciones no idempotentes
POST /payments
Idempotency-Key: uuid-generado-por-cliente-único
Diseño de GraphQL
Reglas de Diseño de Esquemas
- Describe el dominio del negocio, no la estructura de la base de datos
- Usa el patrón de conexiones para listas (preparado para paginación)
- Las mutaciones devuelven el objeto modificado
- Usa enums para conjuntos finitos de valores
- Añade descripciones a todos los tipos y campos
type Query {
user(id: ID!): User
users(filter: UserFilter, pagination: PaginationInput): UserConnection!
}
type Mutation {
createUser(input: CreateUserInput!): CreateUserPayload!
updateUser(id: ID!, input: UpdateUserInput!): UpdateUserPayload!
}
type UserConnection {
edges: [UserEdge!]!
pageInfo: PageInfo!
totalCount: Int!
}
Lista de Verificación de Seguridad de API