HTTP servers en routing in Node.js uitgelegd

Leer hoe HTTP servers en routing werken in Node.js. Van de ingebouwde http-module tot Express routing, met praktische code en best practices.

5 juli 20267 min leestijdDoor We Develop Communication

HTTP servers en routing vormen het fundament van elke Node.js webapplicatie. Of je nu een simpele API bouwt of een volledige webapp, je moet begrijpen hoe een server inkomende verzoeken afhandelt en hoe routing de juiste code aan de juiste URL koppelt.

In deze gids duiken we in de werking van HTTP servers in Node.js, van de ingebouwde http-module tot geavanceerde routing met Express. Je leert hoe je routes definieert, parameters uitleest en een schaalbare structuur opzet.

We bouwen voort op eerdere onderwerpen zoals hoe je een eerste Node.js server bouwt en hoe modules en project structuur werken. Klaar? Tijd om routing onder de knie te krijgen.

Wat is een HTTP server?

Een HTTP server is een programma dat luistert op een specifieke poort (bijvoorbeeld 3000 of 80) en reageert op inkomende HTTP-verzoeken van clients, zoals een browser of een andere applicatie.

Het verzoek bevat een methode (GET, POST, PUT, DELETE), een URL (het pad), headers en soms een body. De server verwerkt dit verzoek en stuurt een antwoord terug met een statuscode (zoals 200 OK of 404 Not Found) en inhoud.

In Node.js draait dit allemaal op één thread, maar dankzij de non-blocking event loop kan een server duizenden gelijktijdige verbindingen afhandelen zonder vast te lopen.

Het request-response model

HTTP werkt volgens een strikt request-response patroon. De client stuurt een verzoek, de server antwoordt, zo simpel is het. Elk verzoek staat op zichzelf; HTTP is een stateless protocol.

Voor meer context over hoe Node.js verzoeken tegelijk kan afhandelen, lees je hoe de event loop werkt.

De ingebouwde http-module

Node.js heeft standaard een http-module waarmee je direct een server kunt starten. Geen npm install, geen dependencies, het werkt out-of-the-box.

const http = require('http');

const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('Hallo wereld!');
});

server.listen(3000, () => {
  console.log('Server draait op http://localhost:3000');
});

Bij elk binnenkomend verzoek wordt de callback aangeroepen met twee objecten: req (het request) en res (de response). Je schrijft de statuscode en headers, en sluit af met res.end().

Request-object analyseren

Het req-object bevat waardevolle informatie die je nodig hebt voor routing en verwerking:

  • req.url, het pad van het verzoek, bijvoorbeeld /users/42
  • req.method, de HTTP-methode, zoals GET of POST
  • req.headers, een object met alle request headers
  • req.on('data', ...), stream voor het uitlezen van de request body

Voor een eenvoudige GET-API heb je meestal alleen req.url en req.method nodig.

Routing met de http-module

Routing betekent dat je op basis van URL en methode bepaalt welke code moet draaien. Zonder framework schrijf je dit handmatig met conditionele logica.

const server = http.createServer((req, res) => {
  if (req.method === 'GET' && req.url === '/') {
    res.writeHead(200, { 'Content-Type': 'text/html' });
    res.end('<h1>Homepagina</h1>');
  } else if (req.method === 'GET' && req.url === '/about') {
    res.writeHead(200, { 'Content-Type': 'text/html' });
    res.end('<h1>Over ons</h1>');
  } else {
    res.writeHead(404, { 'Content-Type': 'text/plain' });
    res.end('Pagina niet gevonden');
  }
});

Dit werkt prima voor een paar routes, maar zodra je applicatie groeit, wordt dit onoverzichtelijk. Denk aan query parameters, dynamische URL-segmenten, of het uitlezen van een JSON body, je krijgt al snel een enorme if/else-boom.

Wanneer de http-module volstaat

De kale http-module is geschikt als je:

  • Een kleine microservice bouwt met twee of drie endpoints
  • Een ultra-lichtgewicht setup nodig hebt zonder dependencies
  • Lage-niveau controle wilt over request/response streams
  • Performance tot op de laatste microseconde wilt optimaliseren

Voor alles daarboven kun je beter een framework gebruiken.

Express: routing gemakkelijk gemaakt

Express is het populairste framework in het Node.js-ecosysteem. Het biedt een schone API voor routing, middleware en request-handling zonder de onderliggende http-module te verbergen.

Installeer Express in je project:

npm install express

Een basisserver met Express ziet er als volgt uit:

const express = require('express');
const app = express();

app.get('/', (req, res) => {
  res.send('Homepagina');
});

app.get('/about', (req, res) => {
  res.send('Over ons');
});

app.listen(3000, () => {
  console.log('Server draait op poort 3000');
});

Je ziet direct hoeveel leesbaarder dit is. Elke route is een aparte methode-aanroep met een duidelijke handler.

HTTP-methoden ondersteunen

Express heeft methoden voor alle HTTP-verben:

app.get('/products', listProducts);
app.post('/products', createProduct);
app.put('/products/:id', updateProduct);
app.delete('/products/:id', deleteProduct);
app.patch('/products/:id', patchProduct);

Met app.all() vang je elke methode tegelijk op, handig voor generieke middleware of logging.

Route parameters en query strings

Dynamische routes zijn essentieel voor echte applicaties. Je wilt bijvoorbeeld een specifieke gebruiker ophalen via /users/42 zonder voor elk ID een aparte route te schrijven.

Route parameters

In Express gebruik je een dubbele punt om een parameter te definiëren:

app.get('/users/:id', (req, res) => {
  const userId = req.params.id;
  res.send(`Gebruiker met ID: ${userId}`);
});

Meerdere parameters zijn ook mogelijk:

app.get('/blogs/:category/:slug', (req, res) => {
  const { category, slug } = req.params;
  res.send(`Categorie: ${category}, artikel: ${slug}`);
});

Query strings

Query parameters (het deel na de ? in een URL) haal je op via req.query:

app.get('/search', (req, res) => {
  const term = req.query.q;
  const page = req.query.page || 1;
  res.send(`Zoekterm: ${term}, pagina: ${page}`);
});

Een verzoek naar /search?q=nodejs&page=2 levert term = 'nodejs' en page = '2' op.

Middleware in Express

Middleware zijn functies die tussen het inkomende verzoek en de uiteindelijke handler draaien. Ze kunnen het verzoek wijzigen, responses versturen, of doorgeven aan de volgende middleware met next().

app.use((req, res, next) => {
  console.log(`${req.method} ${req.url}`);
  next();
});

app.use(express.json());

De express.json() middleware parseert automatisch JSON-bodies, zodat je ze via req.body kunt uitlezen. Vroeger had je hiervoor de aparte body-parser nodig, maar dat is sinds Express 4.16 ingebouwd.

Volgorde is belangrijk

Middleware wordt in volgorde van registratie uitgevoerd. Zorg dat parsing-middleware vóór je routes staat, en error-handlers juist ná je routes.

Router modules voor modulaire structuur

Zodra je applicatie groeit, wil je routes niet allemaal in één bestand hebben. Express heeft hiervoor Router-objecten waarmee je routes opsplitst in modules.

// routes/users.js
const express = require('express');
const router = express.Router();

router.get('/', (req, res) => res.send('Alle gebruikers'));
router.get('/:id', (req, res) => res.send(`Gebruiker ${req.params.id}`));
router.post('/', (req, res) => res.send('Nieuwe gebruiker'));

module.exports = router;

In je hoofdbestand mount je de router op een bepaald pad:

// app.js
const userRoutes = require('./routes/users');
app.use('/users', userRoutes);

Zo blijft je codebase overzichtelijk, zelfs met tientallen routes. Voor meer tips over het opzetten van je project, zie onze gids over modules en project structuur.

Error handling en statuscodes

Een professionele API stuurt duidelijke foutmeldingen en correcte statuscodes. Express heeft een dedicated error-handling middleware met vier parameters:

app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({ error: 'Er ging iets mis' });
});

Veelgebruikte statuscodes om te kennen:

  • 200 OK, succesvol verzoek
  • 201 Created, nieuw resource aangemaakt
  • 400 Bad Request, ongeldig verzoek van de client
  • 401 Unauthorized, authenticatie ontbreekt
  • 404 Not Found, route of resource bestaat niet
  • 500 Internal Server Error, onverwachte fout op de server

Voor een complete lijst raadpleeg de MDN HTTP status documentatie.

Async handlers en promises

Moderne routes werken vaak met databases of externe APIs, wat asynchrone code vereist. Gelukkig ondersteunt Express async/await direct in route handlers.

app.get('/users/:id', async (req, res, next) => {
  try {
    const user = await db.users.findById(req.params.id);
    if (!user) return res.status(404).json({ error: 'Niet gevonden' });
    res.json(user);
  } catch (err) {
    next(err);
  }
});

Let op: vergeet nooit de try/catch of een wrapper-functie zoals express-async-handler, anders kunnen unhandled rejections je server laten crashen. Dieper op dit onderwerp gaan we in in ons artikel over async programming met promises en async/await.

Alternatieven voor Express

Express is de de-facto standaard, maar er zijn moderne alternatieven:

  • Fastify, zeer snel, schema-gebaseerde validatie, ingebouwde logging
  • Koa, gemaakt door hetzelfde team als Express, met moderne async-first API
  • Hapi, configuratie-gedreven, sterk in enterprise-omgevingen
  • NestJS, opinionated framework met TypeScript, modules en dependency injection

Voor beginners blijft Express de beste keus vanwege de enorme community, documentatie en overvloed aan tutorials.

Best practices voor productie

Een paar principes die het verschil maken tussen hobbyprojecten en productieklare servers:

  • Gebruik environment variabelen voor poorten, secrets en database-URLs
  • Log elke request met middleware zoals morgan of pino
  • Valideer user input met libraries zoals zod of joi
  • Zet CORS correct op met de cors-middleware
  • Gebruik helmet voor security headers out-of-the-box
  • Implementeer rate limiting om misbruik te voorkomen
  • Houd routes klein, laat de handler delegeren naar service-modules

Deze gewoontes zorgen voor een server die schaalbaar, veilig en onderhoudbaar blijft.

Veelgestelde vragen

Wat is een HTTP server in Node.js?

Een HTTP server in Node.js is een proces dat luistert naar inkomende HTTP-verzoeken en daarop reageert. Node.js heeft een ingebouwde http-module waarmee je zonder frameworks een server kunt draaien.

Wat is het verschil tussen de http-module en Express?

De http-module is laag-niveau en vereist dat je zelf routing, parsing en middleware bouwt. Express is een framework bovenop http dat deze zaken abstraheert, zodat je sneller productieklare applicaties ontwikkelt.

Hoe werkt routing in Node.js?

Routing koppelt een URL en HTTP-methode aan een specifieke handlerfunctie. In de http-module doe je dit handmatig met if-statements, in Express met methodes als app.get() en app.post().

Wat zijn route parameters?

Route parameters zijn dynamische delen van een URL, zoals /users/:id. Je gebruikt ze om variabele waarden uit de URL te halen, bijvoorbeeld een gebruikers-ID of productnaam.

Moet ik altijd Express gebruiken voor routing?

Nee, voor kleine projecten of microservices volstaat de ingebouwde http-module prima. Express is aan te raden zodra je meerdere routes, middleware of een modulaire structuur nodig hebt.

Veelgestelde vragen

Klaar om digitaal te groeien?

Wij helpen Nederlandse bedrijven met webtechnologie en SEO-strategieën die écht werken. Neem vrijblijvend contact op.