Skip to content

05. Estándar de APIs REST

CampoValor
CódigoSTD-API
Versión1.0
EstadoVigente
PropietarioTech Lead Backend / Docente
Fecha2026-08-30

Garantizar que todos los endpoints del proyecto, sin importar qué equipo los construya, tengan la misma forma, el mismo comportamiento de errores y la misma semántica HTTP.

ReglaEjemplo correctoEjemplo incorrecto
Recursos en plural, kebab-case/api/v1/invoices/api/v1/getInvoice
Sin verbos en la URL (el verbo lo da el método HTTP)POST /api/v1/invoices/api/v1/createInvoice
Anidación solo cuando hay dependencia real/api/v1/invoices/{invoice}/items/api/v1/invoice-items?invoice_id=1 (aceptable solo si items también se consulta de forma independiente)
Versionado en la URL/api/v1/...sin versión
VerboUsoIdempotente
GETLeer un recurso o colecciónSí
POSTCrear un recursoNo
PUTReemplazar un recurso completoSí
PATCHActualizar parcialmente un recursoNo (pero se recomienda diseñarlo idempotente cuando sea posible)
DELETEEliminar un recursoSí

4. HTTP status codes — tabla de referencia obligatoria

Section titled “4. HTTP status codes — tabla de referencia obligatoria”
CódigoUso
200 OKLectura u operación exitosa con cuerpo de respuesta
201 CreatedRecurso creado (incluye Location o el recurso en el body)
204 No ContentOperación exitosa sin cuerpo (ej. DELETE)
400 Bad RequestSolicitud mal formada (JSON inválido, parámetros incorrectos)
401 UnauthorizedNo autenticado
403 ForbiddenAutenticado pero sin permiso
404 Not FoundRecurso no existe
409 ConflictConflicto de estado (ej. duplicado)
422 Unprocessable EntityValidación de datos fallida (estándar en Laravel)
429 Too Many RequestsRate limit excedido
500 Internal Server ErrorError no controlado del servidor

Regla P0/OBLIGATORIO: nunca devolver 200 OK con un error dentro del body ({"error": true} con status 200). El código HTTP siempre refleja el resultado real.

{
"data": {
"id": 12,
"type": "invoice",
"total_amount": "1500.00",
"status": "paid",
"created_at": "2026-08-20T10:00:00Z"
}
}
{
"data": [ { "id": 1, "...": "..." }, { "id": 2, "...": "..." } ],
"meta": {
"current_page": 1,
"per_page": 15,
"total": 42
},
"links": {
"next": "/api/v1/invoices?page=2",
"prev": null
}
}

Este es el formato mínimo que el proyecto exige. LengthAwarePaginator de Laravel (->paginate()), envuelto en una ResourceCollection, produce por defecto una estructura más amplia (meta con from, to, last_page, path, links[]; links con first, last). Se acepta el default de Laravel siempre que incluya, como mínimo, data, meta.current_page, meta.per_page, meta.total y links.next/links.prev. Si se personaliza, el formato debe ser idéntico en todos los endpoints paginados.

Response de error (formato único en todo el proyecto)

Section titled “Response de error (formato único en todo el proyecto)”
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Los datos enviados no son válidos.",
"details": {
"total_amount": ["El monto total es obligatorio."]
}
}
}
  • Todo error de validación devuelve 422 con el formato de la sección 5 — P1/OBLIGATORIO. En Laravel, esto ya es el comportamiento por defecto de un FormRequest; se estandariza el formato de salida mediante el manejador de excepciones central.
  • Los errores 500 nunca exponen el stack trace ni mensajes internos en producción; en desarrollo sí, para depuración — P0/OBLIGATORIO.
ParámetroEjemploComportamiento
page, per_page?page=2&per_page=20Paginación estándar (Laravel paginate())
Filtros?status=paid&user_id=5Un parámetro por campo filtrable, documentado por endpoint
Ordenamiento?sort=-created_atPrefijo - para descendente; se documenta qué campos son ordenables

per_page tiene un máximo definido por el backend (ej. 100) para evitar abuso — P1/OBLIGATORIO.

  • Autenticación vía Laravel Sanctum (tokens, adecuado para SPA/API separada de este proyecto) — RECOMENDADO como default; OAuth2 completo (Passport) es AVANZADO y solo si se justifica.
  • Todo endpoint que no sea explícitamente público requiere autenticación (auth:sanctum) — P0/OBLIGATORIO.
  • La autorización de “quién puede hacer qué” se resuelve con Policies (Doc. 02), no con if dispersos en el controlador — P1/OBLIGATORIO.
  • Se versiona desde el día uno con /api/v1/ aunque solo exista una versión — P1/OBLIGATORIO. Evita romper contratos con el frontend cuando el proyecto crezca.
  • Un breaking change de contrato (quitar/renombrar un campo, cambiar un tipo) requiere v2, no se modifica v1 en producción — P2/RECOMENDADO (AVANZADO en la práctica, dado el alcance del proyecto, pero la regla de versionar desde el inicio sí es obligatoria).
  • PUT y DELETE deben ser idempotentes: llamarlos dos veces con los mismos datos produce el mismo estado final — P1/OBLIGATORIO.
  • Operaciones críticas no idempotentes por naturaleza (ej. procesar un pago) deben prevenir duplicados con una clave de idempotencia o validación de estado previo — P2/RECOMENDADO (AVANZADO en implementación con Idempotency-Key header).
  • snake_case para claves JSON (consistente con las columnas de PostgreSQL) — P1/OBLIGATORIO.
  • Fechas en formato ISO 8601 (2026-08-20T10:00:00Z) — P1/OBLIGATORIO.
  • Nunca se devuelven campos sensibles (password, remember_token) — P0/OBLIGATORIO (se controla en el Resource, Doc. 02).
  • Cada endpoint se documenta (mínimo: método, ruta, parámetros, ejemplo de request/response, códigos de error posibles) en docs/api/ o vía anotaciones OpenAPI (l5-swagger) — P1/OBLIGATORIO desde Fase 3 (ver Doc. 16).

Las reglas P0/P1 de este documento, para su referencia desde la Matriz de Cumplimiento (Doc. 14):

IDReglaPrioridadSección
STD-API-01El código HTTP siempre refleja el resultado real; nunca 200 OK con un error en el body.P04
STD-API-02Todo error de validación devuelve 422 con el formato único de la sección 5.P16
STD-API-03Los errores 500 no exponen stack trace ni mensajes internos en producción.P06
STD-API-04per_page tiene un máximo definido por el backend.P17
STD-API-05Todo endpoint no explícitamente público requiere autenticación (auth:sanctum).P08
STD-API-06La autorización se resuelve con Policies, no con if dispersos en el controlador.P18
STD-API-07Se versiona desde el inicio con /api/v1/.P19
STD-API-08PUT y DELETE son idempotentes.P110
STD-API-09Claves JSON en snake_case.P111
STD-API-10Fechas en formato ISO 8601.P111
STD-API-11Nunca se devuelven campos sensibles (password, remember_token).P011
STD-API-12Cada endpoint se documenta (método, ruta, parámetros, ejemplos, códigos de error).P112
ReglaVerificaciónHerramienta
Formato de respuesta consistenteManual + pruebasFeature/API tests (Doc. 08) + Code Review
Status codes correctosAutomática (parcial)Tests de API que aseveran el status
Naming de rutasAutomática (revisión de routes/api.php) + manualCode Review
Documentación de endpoint actualizadaManualChecklist de PR (Doc. 13)
Autenticación/autorización aplicadaAutomática (tests) + manualTests + Code Review
  • Estándares REST generales (Richardson Maturity Model como referencia conceptual, no como exigencia estricta de nivel 3/HATEOAS).
  • Doc. 02 (Backend) para el mapeo de excepciones.
  • Doc. 09 (Seguridad) para rate limiting, CORS, autenticación.

Fin del documento 05. Continúa en 06. Estándar de Git y Control de Versiones.