¿Cómo diseñar una buena API REST? Guía práctica

Guía práctica para crear una API REST predecible, segura y evolutiva: recursos, semántica HTTP, errores, paginación, versiones, documentación y Laravel.
Una buena API REST resulta predecible. Un desarrollador puede anticipar una ruta, comprender la respuesta sin leer el servidor y resolver errores sin adivinar. Esa calidad nace de decisiones consistentes y de un contrato claro.
¿Qué hace buena a una API REST?
Una API sólida modela recursos del negocio, respeta la semántica HTTP, ofrece JSON consistente, devuelve errores accionables, protege los datos y evoluciona sin romper clientes existentes.
1. Diseña recursos con sustantivos
Representa conceptos estables como orders, customers e invoices. Usa plurales y rutas como /orders/42/items en lugar de /getOrderItems. Mantén poca profundidad para simplificar permisos y mantenimiento.
GET /api/v1/orders
POST /api/v1/orders
GET /api/v1/orders/42
PATCH /api/v1/orders/42
DELETE /api/v1/orders/42
2. Respeta los métodos HTTP
GET lee sin modificar estado; POST crea o inicia una operación no idempotente; PUT reemplaza; PATCH actualiza parcialmente; DELETE elimina. Seguir RFC 9110 permite que clientes, cachés y herramientas funcionen correctamente.
3. Devuelve códigos de estado precisos
Usa 200 para éxito, 201 con Location al crear y 204 sin cuerpo. Diferencia 400, 401, 403, 404, 409, 422 y 429. Reserva 5xx para fallos del servidor, no para errores del cliente.
4. Mantén representaciones JSON consistentes
Define una convención para nombres, fechas, dinero, valores nulos y envoltorios. Usa ISO 8601 con zona horaria. No expongas columnas de base de datos accidentalmente: la respuesta es un contrato público.
{
"data": {
"id": 42,
"status": "paid",
"total": 129.90,
"currency": "USD"
}
}
5. Crea errores útiles
Incluye un tipo o código estable, título, estado HTTP, detalle seguro, errores por campo y un identificador de solicitud. RFC 9457 Problem Details proporciona un formato estándar.
{
"type": "https://api.example.com/problems/validation",
"title": "Validation failed",
"status": 422,
"detail": "One or more fields are invalid.",
"errors": {"email": ["The email field is required."]}
}
6. Estandariza colecciones
Utiliza parámetros explícitos: ?status=paid&sort=-created_at&page=2&per_page=25. Documenta filtros y ordenaciones permitidos y fija un máximo por página. La paginación por cursor es mejor para conjuntos grandes o cambiantes.
7. Planifica compatibilidad y versiones
Añadir campos opcionales suele ser compatible; renombrar, cambiar tipos o eliminar comportamiento rompe clientes. Adopta una estrategia como /api/v1, un periodo de deprecación y notas de migración.
8. Integra la seguridad
Exige HTTPS, autentica y autoriza cada acción sobre el recurso. Valida con listas permitidas, limita el tamaño y la frecuencia de solicitudes y nunca expongas secretos ni stack traces. Registra eventos de seguridad sin credenciales ni datos personales.
9. Caché y concurrencia
Usa Cache-Control, ETag y peticiones condicionales en lecturas seguras. Acepta If-Match o una versión para evitar sobrescrituras. Las claves de idempotencia protegen reintentos de pagos y creaciones.
10. Documenta y prueba
Mantén un contrato OpenAPI con ejemplos de éxito, validación, autenticación y rate limiting. Úsalo para documentación, SDK, validación y pruebas de contrato. Añade IDs de correlación, logs estructurados, métricas y trazas.
Una API REST limpia con Laravel
Laravel ofrece rutas CRUD convencionales con Route::apiResource, autenticación con Sanctum y límites mediante middleware.
use App\Http\Controllers\Api\OrderController;
use Illuminate\Support\Facades\Route;
Route::prefix('v1')
->middleware(['auth:sanctum', 'throttle:api'])
->group(function () {
Route::apiResource('orders', OrderController::class);
});Usa Form Requests para validación y autorización, Policies para permisos y API Resources para controlar JSON. Mantén el controlador centrado en HTTP y coloca la lógica compleja en servicios o acciones.
public function show(Order $order): OrderResource
{
return new OrderResource($order);
}
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'status' => $this->status,
'total' => $this->total,
'currency' => $this->currency,
];
}
Checklist de diseño
- URLs de recursos claras y plurales
- Métodos y estados HTTP correctos
- JSON estable y errores Problem Details
- Filtros, orden y paginación documentados
- Autenticación, autorización, validación y límites
- Política de compatibilidad y versiones
- OpenAPI, pruebas de contrato y observabilidad
Preguntas frecuentes
¿Las URLs deben incluir verbos?
Normalmente no. Usa sustantivos y métodos HTTP; un comando de negocio puede modelarse como recurso, por ejemplo POST /orders/42/cancellation.
¿Cuál es la regla principal?
La consistencia: una convención razonable aplicada siempre supera a endpoints ingeniosos que se comportan de forma distinta.
Artículos destacados

Kafka en producción: particiones, lag, fiabilidad y respuesta a incidentes
Una guía práctica para tomar decisiones de orden, capacidad y recuperación en Kafka, interpretar el lag y responder a fallos sin perder de vista el resultado de negocio.

Laravel y Kafka sin eventos perdidos: outbox transaccional y consumidores idempotentes con PostgreSQL
Una confirmación en PostgreSQL y una publicación en Kafka no forman una transacción ordinaria. Aprende a evitar pérdidas y duplicación de efectos.

Apache Kafka explicado: temas, particiones, grupos de consumidores y tu primer flujo de eventos
Sigue un evento de pedido desde el productor hasta varios consumidores y prueba en local cómo funcionan las particiones, el orden y la reproducción.
Comentarios
0 comentariosTodavía no hay comentarios aprobados. Las respuestas nuevas pueden esperar moderación.