Express.js
Construir responses HTTP correctas
Construcción coherente de respuestas mediante status, headers, body, serialización, cache, redirects y streaming.
- Última actualización
- Actualizada
- Nivel
- Fundamentos
Express.js
Construcción coherente de respuestas mediante status, headers, body, serialización, cache, redirects y streaming.
Responder correctamente no significa solo serializar JSON. La aplicación debe traducir un resultado interno a:
status code
+ headers
+ body opcionalEl cliente, una cache, un proxy y una herramienta de observabilidad toman decisiones a partir de esa combinación.
Devolver siempre 200 con { success: false } obliga a cada consumidor a inventar reglas propias. Los status y headers permiten reutilizar semántica HTTP para creación, cache, redirects, retries y errores.
response.status(200).json({ data: order });json() serializa, configura Content-Type: application/json y finaliza la response.
response
.status(201)
.location(`/orders/${order.id}`)
.json({ data: order });201 Created comunica que el recurso fue creado. Location identifica su URI cuando aplica.
response.status(204).end();Un 204 no debe incluir body. Si el cliente necesita la representación actualizada, responde 200 con JSON.
Serializa JSON. No envíes entidades internas sin revisar campos sensibles.
Selecciona comportamiento según el valor. Es útil, pero una API suele ganar claridad usando helpers explícitos.
Finaliza sin contenido adicional.
Envía el texto estándar del status. Puede romper un contrato JSON uniforme.
Construye redirect. Valida destinos para evitar open redirects.
Envía archivo y maneja parte del streaming. Requiere rutas seguras, errores y headers correctos.
Los headers deben configurarse antes del body:
response.set({
'Cache-Control': 'private, no-store',
'X-Request-Id': requestId,
});Algunos headers importantes:
Content-Type: representación.Location: recurso creado o destino.Cache-Control: política de cache.ETag: validador de representación.Vary: dimensiones que cambian la respuesta.Retry-After: espera sugerida.WWW-Authenticate: reto de autenticación.Allow: métodos permitidos para 405.No serialices directamente:
Define DTOs o mappers públicos:
function toOrderResponse(order: Order) {
return {
id: order.id,
status: order.status,
total: order.total,
createdAt: order.createdAt.toISOString(),
};
}const accepted = request.accepts(['application/json']);
if (!accepted) {
response.status(406).json({ code: 'NOT_ACCEPTABLE' });
return;
}Una API exclusivamente JSON puede documentar un único formato. Negotiation completa solo vale la pena cuando realmente existen varias representaciones.
307 y 308 preservan el método. 301 y 302 tienen semántica histórica que algunos clientes transforman a GET.
Nunca hagas:
response.redirect(request.query.returnTo as string);Usa destinos relativos o una whitelist.
Una request HEAD debe producir los mismos headers que GET sin body. Express puede derivarla de GET, pero la aplicación quizá ejecute trabajo costoso igualmente. Si calcular la representación es caro, implementa metadata explícita.
stream.on('error', next);
stream.pipe(response);Una vez iniciados headers, un fallo no puede reemplazarse por JSON. El error handler debe comprobar headersSent, registrar y cerrar o delegar.
Una response debe declarar si puede almacenarse:
response.set('Cache-Control', 'private, max-age=60');No marques como pública una respuesta personalizada o con datos sensibles. Si la respuesta varía por Accept-Encoding, Origin u otro header, utiliza Vary correctamente.
ETag y If-None-Match permiten 304 sin reenviar el body. Express puede generar ETags, pero debes entender si el validador representa realmente la versión del recurso y cómo interactúa con compresión y proxies.
const result = await createOrder.execute(input);
response
.status(201)
.location(`/api/orders/${result.id}`)
.set('Cache-Control', 'private, no-store')
.json({ data: toOrderResponse(result) });Flujo:
JSON.stringify no serializa BigInt por defecto. Conviértelo conscientemente.
Date se serializa a ISO, pero el contrato debe definir timezone y formato.
El body se omite o produce comportamiento inconsistente. No lo uses.
No intentes responder otra vez. Registra y delega según estado.
Comprueba trust proxy, TLS termination y políticas de cache del entorno.
json().next() después de responder.Verifica:
Content-TypeLocationUn envelope uniforme { data, meta } puede simplificar clientes, pero añade ruido en respuestas pequeñas. Un contrato de error uniforme suele aportar más valor que envolver absolutamente todo.
Location?Métodos HTTP y semántica explica cómo la intención de la operación condiciona rutas, retries y caches.