← Node.js: JavaScript fuera del navegador

Sesión 11 · Semana 4

Rutas, métodos y códigos de estado

Hoy · Hoja de ruta

  1. 1. Aprende: Cómo se decide qué hacer según el método y la ruta, y qué estado responder.
  2. 2. Haz: Sirve tu catálogo en /api/productos, leyendo y creando.
  3. 3. Comprueba: Cada situación devuelve el código de estado correcto.

Antes de empezar · 5 minutos, sin apuntes

  1. ¿Qué significan 200, 201, 400, 404 y 500?
  2. ¿Qué método usarías para crear algo? ¿Y para consultarlo?
  3. Si el cliente envía datos inválidos, ¿de quién es el fallo?

Enrutar a mano

const servidor = http.createServer(async (peticion, respuesta) => {
  const url = new URL(peticion.url, `http://${peticion.headers.host}`);
  const ruta = url.pathname;

  if (peticion.method === "GET" && ruta === "/api/productos") {
    return responderJson(respuesta, 200, await listar());
  }

  if (peticion.method === "GET" && ruta.startsWith("/api/productos/")) {
    const id = Number(ruta.split("/").pop());
    const producto = await obtener(id);
    if (!producto) return responderJson(respuesta, 404, { error: "No encontrado" });
    return responderJson(respuesta, 200, producto);
  }

  responderJson(respuesta, 404, { error: "Ruta no encontrada" });
});

Se ve venir el problema: con quince rutas esto es una escalera de condicionales, y cada ruta con parámetro exige partir el texto a mano. Guárdalo en la memoria para la sesión 13.

Leer el cuerpo de una petición

async function leerCuerpo(peticion) {
  const trozos = [];
  for await (const trozo of peticion) trozos.push(trozo);
  const texto = Buffer.concat(trozos).toString("utf8");
  return texto === "" ? null : JSON.parse(texto);
}

El cuerpo llega a trozos

El cuerpo no es una propiedad legible de una sola vez, sino un flujo que llega por fragmentos. Por eso hay que acumular los trozos y solo entonces convertirlos a texto y analizarlos.

Y ese JSON.parse es un dato de fuera: un cuerpo mal formado lanza una excepción que, sin capturar, tumba la petición con un 500 cuando en realidad el fallo es del cliente y merece un 400.

Los códigos que vas a usar

Código Cuándo
200 Todo bien, aquí está
201 Creado; con la cabecera Location
204 Todo bien, no hay nada que devolver
400 La petición está mal formada o los datos no son válidos
401 / 403 No autenticado / autenticado pero sin permiso
404 El recurso no existe
405 El método no está permitido en esta ruta
409 Conflicto: ya existe algo así
500 Se ha roto algo en el servidor

La familia del código dice de quién es el problema

Los 4xx significan «lo has pedido mal»; los 5xx, «se me ha roto a mí». Devolver 200 con un cuerpo que dice «error» rompe esa convención, y cualquier cliente automático —incluido tu propio fetch de la UD4, que mira respuesta.ok— se lo creerá.

Un 500 en tus registros es una tarea pendiente para ti. Un 400 es información para quien llama.

Un formato de error constante

{ "error": "Producto no encontrado", "detalles": [] }

Que todas las respuestas de error tengan la misma forma permite al cliente escribir un solo tratamiento. Es un contrato, y romperlo a mitad de una API es una fuente inagotable de fallos en el cliente.

Tarea 11 · La API a mano

  1. Implementa GET /api/productos con filtro por categoría en la consulta.
  2. Implementa GET /api/productos/:id con su 404.
  3. Implementa POST /api/productos con validación, 201 y cabecera Location.
  4. Devuelve 400 con la lista de errores cuando la validación falle.
  5. Responde 405 si el método no está soportado en una ruta que sí existe.
  6. Escribe un fichero peticiones.http que pruebe los seis casos.
Objetivo mínimoTres rutas con los códigos correctos y el fichero de pruebas.
Si lo tienesAñade paginación con parámetros de consulta.
RetoEnvía un cuerpo JSON inválido y consigue que responda 400 y no 500.

Checkpoint · fin de la sesión 11

  • Decides la acción por método y ruta.
  • Lees el cuerpo acumulando el flujo.
  • Devuelves el código de estado que corresponde a cada caso.
  • Todos tus errores tienen la misma forma.

Antes de cerrar · 2 minutos, sin mirar

  1. ¿Qué diferencia hay entre un 400 y un 500?
  2. ¿Qué se devuelve al crear un recurso?
  3. ¿Por qué el cuerpo se lee por trozos?
Ver respuestas

1 · El 400 dice que la petición estaba mal; el 500, que ha fallado el servidor.

2 · Un 201 con la cabecera Location apuntando al recurso creado.

3 · Porque llega como un flujo, no como un valor ya disponible.