¡Ven a la JSConf España 2026! Comprar entradas

Discriminar rutas y devolver respuestas correctas en Node.js

Hasta ahora tenemos un servidor Node.js escuchando correctamente, pero con una limitación importante: responde lo mismo en cualquier ruta. Da igual si accedemos a /, /usuarios o cualquier otra URL.

En esta clase vamos a aprender a discriminar rutas, devolver respuestas distintas según la URL, manejar correctamente los status codes y enviar JSON bien formado. Estos son los cimientos de cómo funcionan los frameworks modernos.

El problema: todas las rutas responden igual

Si no controlamos la ruta, nuestro servidor se comporta de forma monótona:

  • Responde siempre lo mismo independientemente de la intención del usuario.
  • No diferencia entre recursos (ej. / vs /usuarios).
  • No puede devolver errores de forma semántica (como un 404).

Esto es justo lo que queremos evitar en un backend profesional.

Discriminando rutas con la URL

Node.js nos permite acceder a la URL de la petición a través del objeto req.url. Con esta información, podemos decidir qué lógica ejecutar en cada caso.

import http from 'node:http'

const server = http.createServer((req, res) => {
  const { url } = req

  if (url === '/') {
    res.end('<h1>Bienvenido a la Home</h1>')
  } else if (url === '/usuarios') {
    res.end('<h1>Lista de usuarios</h1>')
  } else {
    res.end('<h1>404 Not Found</h1>')
  }
})

Manejo correcto de códigos de estado

Un error muy común es olvidar indicar el código de estado adecuado. Por defecto, Node.js envía un 200 OK, incluso si el contenido que estás enviando es un mensaje de error.

Los status codes HTTP deben indicarse explícitamente usando la propiedad res.statusCode.

if (url === '/') {
  res.statusCode = 200 // Éxito
  res.end('Home')
} else {
  res.statusCode = 404 // No encontrado
  res.end('No encontrado')
}

Tip: Al establecer correctamente el código de estado, el navegador, las herramientas de desarrollo y los clientes de API (como Postman o Insomnia) pueden interpretar correctamente qué ha sucedido con la petición.

Importancia del return en las respuestas

Un detalle fundamental al programar servidores es detener la ejecución tras enviar una respuesta. Si no usas return después de un res.end(), el código que haya debajo se seguirá ejecutando.

Si Node.js intenta escribir más datos en una respuesta que ya ha terminado, lanzará el error: ERR_HTTP_HEADERS_SENT.

if (url === '/') {
  res.end('Home')
  return // 👈 ¡Fundamental para terminar aquí la ejecución!
}

El problema del Content-Type

Aunque estés devolviendo un objeto convertido a texto, eso no lo convierte automáticamente en un JSON para el cliente.

Si no indicamos el header correcto:

  • El navegador lo interpreta como texto plano (text/plain).
  • Las herramientas no formatean el contenido.
  • El cliente no sabe que debe parsear la respuesta como un objeto.

Para JSON, el header obligatorio debe ser: Content-Type: application/json

Devolver JSON correctamente

Para devolver JSON de forma profesional, debemos hacer dos cosas:

  1. Establecer el header Content-Type.
  2. Convertir el objeto de JavaScript a una cadena de texto con JSON.stringify.
const user = { name: 'midudev', role: 'admin' }

res.setHeader('Content-Type', 'application/json; charset=utf-8')
res.end(JSON.stringify(user))

Unificar la forma de responder

Escribir siempre los mismos headers y conversiones se vuelve repetitivo muy rápido. Una buena práctica es crear una función auxiliar que simplifique este proceso:

const sendResponse = (res, statusCode, data) => {
  res.statusCode = statusCode
  res.setHeader('Content-Type', 'application/json; charset=utf-8')
  res.end(JSON.stringify(data))
}

// Uso mucho más limpio:
if (url === '/api/user') {
  return sendResponse(res, 200, { name: 'midu' })
}

Respuestas de error en formato JSON

Incluso los errores deberían devolverse como JSON. En lugar de enviar texto plano para un 404, es mucho mejor devolver un objeto estructurado:

return sendResponse(res, 404, {
  error: 'Not Found',
  message: 'La ruta solicitada no existe en este servidor',
})

Esto hace que la API sea mucho más predecible y fácil de consumir por otros desarrolladores.

Por qué esto es importante

Todo lo que hemos visto en esta clase es:

  • Exactamente lo que hacen frameworks como Express por debajo (el famoso res.json()).
  • La base para entender cómo se comunican las aplicaciones modernas.
  • La forma de evitar tratar a las librerías como “magia negra”.

Lo que hemos visto

  • ✅ Discriminar rutas manualmente usando req.url.
  • ✅ Manejar correctamente los códigos de estado HTTP.
  • ✅ Usar el header Content-Type para respuestas JSON.
  • ✅ Unificar y simplificar el envío de respuestas.
  • ✅ Devolver errores de forma consistente.

Con esto ya tienes un servidor mucho más realista. En la siguiente clase empezaremos a ver por qué herramientas como Express existen para hacernos la vida más fácil.