API REST: no es solo mandar JSON, es cómo se manda
Última revisión:
General- Diseño de APIs
- HTTP
- Buenas prácticas
Respuesta corta
REST es un estilo de arquitectura, no un estándar: los recursos se identifican con URLs y se manipulan con los verbos HTTP según su semántica, y cada respuesta trae un código de estado que dice qué pasó.
Además es cliente-servidor, stateless y cacheable, lo que permite que cliente y servidor evolucionen por separado y que la API escale.
En esta página
Explicación
Un estilo, no un estándar
REST (Representational State Transfer) lo definió Roy Fielding en su tesis doctoral del año 2000. No es un protocolo ni un estándar: es un conjunto de restricciones de arquitectura que se apoya en estándares que sí existen, como HTTP, las URIs y los media types.
Por eso una API no es REST por usar JSON sobre HTTP, sino por respetar esas restricciones.
Las seis restricciones
| Restricción | Qué significa | Por qué importa |
|---|---|---|
| Cliente-servidor | Cliente y servidor están separados y solo se comunican a través de la API | Evolucionan por separado: una misma API sirve a la web, al móvil y a otros backends |
| Stateless | El servidor no guarda la sesión del cliente; cada request trae todo, incluida la autenticación | Cualquier instancia atiende cualquier request, así que escala horizontalmente |
| Cacheable | Cada respuesta declara si se puede cachear y por cuánto tiempo (Cache-Control, ETag) |
Menos carga en el servidor y respuestas más rápidas |
| Interfaz uniforme | Recursos con URL, manipulados con representaciones y mensajes que se autodescriben | Cualquier cliente entiende la API sin acuerdos especiales |
| Sistema en capas | Puede haber proxies, gateways o una CDN en medio sin que el cliente lo note | Se agrega caché, seguridad o balanceo sin tocar el cliente |
| Código bajo demanda (opcional) | El servidor puede enviar código ejecutable al cliente | Casi no se usa en APIs; es la única restricción opcional |
Un matiz que vale la pena decir: stateless no significa sin base de datos. El servidor sí guarda el estado de los recursos (los pedidos, los usuarios). Lo que no guarda es el estado de la conversación con cada cliente.
Recursos, no acciones
La URL nombra una cosa y el verbo HTTP dice qué hacer con ella: GET /orders/42, no POST /getOrder. Las colecciones van en plural (/orders) y las relaciones se anidan (/orders/42/items).
Lo que viaja no es el recurso en sí, sino una representación suya, normalmente JSON. El header Content-Type indica el formato, así que el mismo recurso podría servirse en otro formato sin cambiar su URL.
Verbos y códigos de estado
| Método | Uso | ¿Seguro? | ¿Idempotente? |
|---|---|---|---|
GET |
Leer | Sí | Sí |
POST |
Crear | No | No |
PUT |
Reemplazar completo | No | Sí |
PATCH |
Modificar en parte | No | No necesariamente |
DELETE |
Eliminar | No | Sí |
Seguro significa que no cambia nada en el servidor. Idempotente, que repetir la request deja el mismo resultado que hacerla una vez. Esto importa en los reintentos: repetir un DELETE no rompe nada, pero repetir un POST puede crear dos pedidos.
La respuesta siempre dice qué pasó con su código de estado: 2xx es éxito, 4xx es un error del cliente y 5xx es un error del servidor. Los que más espero ver en una API:
200 OK,201 Created(con el headerLocationdel recurso nuevo) y204 No Content.400 Bad Request,404 Not Foundy409 Conflict.401 Unauthorized(no sé quién eres) frente a403 Forbidden(sé quién eres, pero no tienes permiso).500 Internal Server Error.
Código
El mismo recurso de pedidos, primero como RPC disfrazado de REST y después respetando las reglas. Fíjate en las URLs, los verbos y los códigos de estado.
Antes (RPC)
### Crear un pedidoPOST /createOrder HTTP/1.1Content-Type: application/json
{ "productId": 7, "quantity": 2 }
HTTP/1.1 200 OKContent-Type: application/json
{ "ok": true, "orderId": 42 }
### Consultar un pedido que no existePOST /getOrder HTTP/1.1Content-Type: application/json
{ "orderId": 99 }
HTTP/1.1 200 OKContent-Type: application/json
{ "ok": false, "error": "Order not found" }Después (REST)
### Crear un pedidoPOST /orders HTTP/1.1Content-Type: application/json
{ "productId": 7, "quantity": 2 }
HTTP/1.1 201 CreatedLocation: /orders/42
### Leer un pedidoGET /orders/42 HTTP/1.1
HTTP/1.1 200 OKContent-Type: application/jsonCache-Control: max-age=60ETag: "a1b2c3"
{ "id": 42, "productId": 7, "quantity": 2, "status": "pending" }
### Eliminar un pedidoDELETE /orders/42 HTTP/1.1
HTTP/1.1 204 No Content
### Leer un pedido que no existeGET /orders/99 HTTP/1.1
HTTP/1.1 404 Not FoundTrade-offs
- Simplicidad frente a flexibilidad. REST usa HTTP tal cual, así que funciona con cualquier cliente y aprovecha la caché y la infraestructura que ya existen. A cambio, la forma de la respuesta la decide el servidor, lo que puede traer datos de más o de menos y obligar a varias llamadas. Para esos casos existen alternativas como GraphQL o gRPC, cada una con sus propios costos.
- Stateless escala, pero cada request carga su contexto. El token viaja y se valida en cada llamada, y eso tiene un costo en tamaño y en procesamiento.
- La caché acelera, pero hay que invalidarla. Si
Cache-ControlyETagno están bien pensados, el cliente puede ver datos obsoletos. - El error típico: RPC disfrazado de REST. Verbos en la URL, todo por
POSTy200con el error en el cuerpo. Funciona, pero pierde la caché, la idempotencia y los códigos de estado que cualquier cliente o proxy sabe interpretar. - Dato adicional: HATEOAS. Es la restricción que casi nadie cumple: que la respuesta incluya enlaces a las acciones posibles, para que el cliente navegue la API sin conocer las URLs de antemano.
Entradas relacionadas
Cloud y DevOps
¿Sabes armar un buen pipeline de CI? Pasos y consideraciones
Un proceso de CI corre en cada push o pull request y responde una pregunta: ¿este cambio se puede integrar a la rama principal sin romper nada? Para eso restaura dependencias, corre el lint, compila, ejecuta los tests y revisa vulnerabilidades, de lo más rápido a lo más lento. Si todo pasa, genera un artefacto versionado y lo publica; si algo falla, se detiene y el PR queda bloqueado. Desplegar ese artefacto ya es CD.
General