Express.js
Validación de entradas no confiables
Explica cómo validar body, params, query y headers como datos no confiables mediante schemas, límites, normalización y mensajes de error seguros.
- Última actualización
- Actualizada
- Nivel
- Fundamentos
Express.js
Explica cómo validar body, params, query y headers como datos no confiables mediante schemas, límites, normalización y mensajes de error seguros.
Validar significa convertir datos externos desconocidos en un valor que la aplicación puede usar con seguridad estructural. No sustituye autorización, reglas de negocio ni constraints de base de datos.
Todo dato de params, query, body, headers, cookies, archivos o servicios externos debe tratarse como unknown hasta comprobarlo.
input externo
→ parsing
→ validación estructural
→ normalización
→ reglas de negocio
→ persistencia con constraintsconst body = request.body as CreateOrderInput;El cast desaparece al compilar. El cliente puede enviar null, strings, arrays o campos inesperados. TypeScript protege el código escrito por el equipo, no los bytes de red.
endDate posterior a startDate.No intentes resolver todas las capas con un único schema HTTP.
const createOrderSchema = z.object({
branchId: z.string().uuid(),
notes: z.string().trim().max(500).optional(),
items: z.array(z.object({
productId: z.string().uuid(),
quantity: z.number().int().min(1).max(100),
}).strict()).min(1).max(50),
}).strict();Este schema garantiza forma y límites. No garantiza que los productos existan ni que la branch pertenezca al actor.
function validateBody<T>(schema: ZodType<T>): RequestHandler {
return (request, response, next) => {
const result = schema.safeParse(request.body);
if (!result.success) {
next(new RequestValidationError(toPublicIssues(result.error)));
return;
}
response.locals.validatedBody = result.data;
next();
};
}No expongas directamente la estructura de error de la librería como contrato permanente. Mapea a paths y códigos propios.
Query params llegan como strings. Coercion puede ser útil:
z.coerce.number().int().min(1).max(100)Pero evita conversiones ambiguas. Define qué ocurre con '', ' ', '01', 'true' o fechas locales.
Tres políticas:
Útil para comandos sensibles y detectar errores del cliente.
Puede facilitar compatibilidad, pero el cliente podría creer que el campo se aplicó.
Solo cuando el dominio acepta metadata extensible y existe control posterior.
Elige por endpoint, no por costumbre.
Normalizar crea una representación canónica:
No normalices datos cuya forma original importa. Los nombres de persona, contraseñas y contenido firmado requieren cuidado.
Sanitizar depende del contexto de salida. Escapar HTML no es lo mismo que validar un nombre. Una API JSON no debe “limpiar” cadenas indiscriminadamente; debe preservar datos y escapar al renderizar en el contexto correcto.
Aunque un body incluya:
{ "role": "admin" }puede ser estructuralmente válido y aun así no estar permitido. La validación no decide privilegios.
Dos requests pueden validar el mismo email como disponible y competir. La unique constraint ofrece la garantía final. El caso de uso debe traducir la violación a un conflicto comprensible.
Valida:
const parsed = createOrderSchema.parse(request.body);
const result = await createOrder.execute({
actor: response.locals.actor,
input: parsed,
});Flujo:
{
"code": "VALIDATION_ERROR",
"details": [
{
"path": "items.0.quantity",
"code": "TOO_SMALL",
"message": "La cantidad debe ser mayor que cero"
}
]
}Los códigos deben ser estables. Los mensajes pueden localizarse y cambiar.
No son equivalentes. Define si null borra, representa desconocido o es inválido.
Validar un objeto parcial no garantiza una transición válida. Combina con estado actual.
Un ISO string válido puede representar un instante fuera del rango permitido. Convierte y valida timezone y dominio.
Evita floats cuando precisión importa. Valida unidades menores o decimal explícito.
Strings visualmente similares pueden tener representaciones distintas. Normaliza solo cuando el caso lo necesita.
Incluye:
Schemas estrictos detectan errores temprano, pero pueden dificultar evolución compatible. Tolerancia indiscriminada facilita clientes viejos, pero oculta bugs. Diseña versionado y defaults conscientemente.
Manejo de errores en Express 5 explica cómo los fallos atraviesan el pipeline sin convertirse en respuestas inconsistentes.