Express.js ist seit über einem Jahrzehnt das Rückgrat unzähliger Node.js-Projekte. Als minimales, unopinioniertes Web-Framework legt es keine starre Projektstruktur vor, bietet aber alle Bausteine, die für die Entwicklung von REST-APIs und Webservern benötigt werden. Dieser Artikel erklärt die wichtigsten Konzepte und zeigt, warum Express trotz jüngerer Konkurrenz nach wie vor relevant ist.
Was ist Express.js?
Express.js ist ein schlankes Web-Framework für Node.js, das erstmals 2010 veröffentlicht wurde. Es abstrahiert die rohe Node.js-HTTP-API und stellt eine einfachere Schnittstelle für Routing, Middleware-Verwaltung und Request-Handling bereit. Express selbst bringt kaum Funktionalität mit – stattdessen setzt es auf ein ökosystem von Middleware-Paketen, die je nach Bedarf eingebunden werden.
Dieses Prinzip macht Express extrem flexibel: Wer eine einfache statische Datei-Auslieferung benötigt, nutzt zwei Zeilen Code. Wer eine vollständige REST-API mit Authentifizierung, Datenbankzugriff und Validierung baut, kann die Architektur frei wählen. Die offizielle Dokumentation ist unter expressjs.com verfügbar.
Routing: GET, POST, PUT, DELETE
Routing in Express bedeutet, HTTP-Methoden und URL-Pfade mit Handler-Funktionen zu verbinden. Die Syntax ist dabei direkt und lesbar:
const express = require('express');
const app = express();
app.get('/users', (req, res) => {
res.json({ users: [] });
});
app.post('/users', (req, res) => {
// Neuen Nutzer anlegen
res.status(201).json({ created: true });
});
app.put('/users/:id', (req, res) => {
res.json({ updated: req.params.id });
});
app.delete('/users/:id', (req, res) => {
res.status(204).send();
});
app.listen(3000);
URL-Parameter werden mit dem Doppelpunkt-Präfix definiert (z. B. :id) und über req.params ausgelesen. Query-Parameter stehen über req.query zur Verfügung. Express unterstützt außerdem reguläre Ausdrücke und Platzhaltermuster für komplexere URL-Strukturen.
Für größere Projekte empfiehlt sich die Nutzung von express.Router(), um Routen in separate Module aufzuteilen und nach Feature oder Ressource zu gruppieren.
Das Middleware-Konzept
Middleware ist das Herzstück von Express. Eine Middleware-Funktion hat Zugriff auf das Request-Objekt (req), das Response-Objekt (res) und die next-Funktion, die den Aufruf der nächsten Middleware in der Kette auslöst. Jede eingehende Anfrage durchläuft die registrierten Middlewares in der Reihenfolge ihrer Registrierung.
Typische Middleware-Aufgaben sind: Logging, Authentifizierungsprüfung, Request-Body-Parsing, CORS-Header-Setzung und Rate-Limiting. Middlewares können global (für alle Routen) oder lokal (nur für bestimmte Routen) registriert werden.
body-parser und CORS
Zwei der am häufigsten eingesetzten Middleware-Pakete sind body-parser und cors. Seit Express 4.16 ist body-parser für JSON und URL-encoded Bodies bereits integriert:
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
Für Cross-Origin-Anfragen wird das cors-Paket eingesetzt:
const cors = require('cors');
app.use(cors({ origin: 'https://meinefrontend.de' }));
Fehlerbehandlung mit Error-Handling-Middleware
Express unterscheidet reguläre Middleware (drei Parameter: req, res, next) von Error-Handling-Middleware (vier Parameter: err, req, res, next). Letztere fängt Fehler ab, die in vorherigen Middlewares oder Routen mit next(err) weitergereicht wurden:
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(err.status || 500).json({
error: err.message || 'Interner Serverfehler'
});
});
Wichtig: Die Error-Handling-Middleware muss als letztes registriert werden, nach allen Routen und normalen Middlewares.
express-async-errors, um unbehandelte Promise-Rejections automatisch an die Error-Handling-Middleware weiterzuleiten. Ab Express 5 (aktuell im Release-Candidate-Stadium) werden async-Fehler automatisch abgefangen.
Statische Dateien ausliefern
Express kann mit wenigen Zeilen als statischer Dateiserver fungieren:
app.use(express.static('public'));
Alle Dateien im Verzeichnis public werden damit direkt unter dem Root-Pfad erreichbar. Das eignet sich für einfache Single-Page-Applications oder für die Auslieferung von Assets wie Bilder, CSS und JavaScript-Bundles.
Typische REST-API-Struktur
Eine gut organisierte Express-API folgt üblicherweise dieser Ordnerstruktur:
src/
routes/ ← Router-Definitionen pro Ressource
controllers/ ← Request-Handling-Logik
services/ ← Geschäftslogik und Datenbankzugriff
middleware/ ← Eigene Middlewares (auth, validation)
app.js ← Express-App-Konfiguration
server.js ← HTTP-Server-Start
Diese Trennung sorgt für Wartbarkeit und Testbarkeit. Controller-Funktionen delegieren Logik an Services, was Unit-Tests ohne HTTP-Layer ermöglicht.
Vergleich: Express.js vs. Fastify vs. Hono vs. Koa
| Kriterium | Express.js | Fastify | Hono | Koa |
|---|---|---|---|---|
| Requests/Sekunde (grob) | ~50.000 | ~80.000 | ~120.000+ | ~55.000 |
| TypeScript-Support | Via @types/express | Eingebaut | Eingebaut (first-class) | Via @types/koa |
| Bundle-Größe | ~208 KB | ~1,1 MB | ~15 KB | ~26 KB |
| Ökosystem / Middleware | Sehr groß | Groß (Plugins) | Wachsend | Mittel |
| Schema-Validierung | Externe Pakete (joi, zod) | Eingebaut (JSON Schema) | Via Zod/Valibot | Externe Pakete |
| Edge-Runtime-fähig | Nein | Nein | Ja (Cloudflare, Deno, Bun) | Nein |
Eine detaillierte Benchmark-Übersicht stellt das Fastify-Projekt regelmäßig bereit. Hono ist besonders für Edge-Deployments interessant, da es auf der Web-Standard-API (Request/Response) aufbaut.
Häufig gestellte Fragen
- Ist Express.js für Produktionsumgebungen geeignet?
- Ja, Express läuft in zahlreichen großen Produktionssystemen. Für einfache bis mittlere APIs ist es nach wie vor eine solide Wahl. Bei sehr hohen Anforderungen an Durchsatz oder strikter Typsicherheit bieten Fastify oder NestJS Vorteile.
- Kann ich Express.js mit TypeScript verwenden?
- Ja. Mit dem Paket
@types/expressaus DefinitelyTyped stehen vollständige Typdefinitionen zur Verfügung. Alternativ kann Express zusammen mitts-nodeoder einem Build-Schritt mittsceingesetzt werden. - Was ist der Unterschied zwischen Express.js und Koa?
- Koa wurde von den ursprünglichen Express-Entwicklern als modernerer Nachfolger konzipiert. Es verwendet async/await-Middleware statt des Callback-basierten Ansatzes von Express und hat einen kleineren Core. Das Ökosystem von Koa ist jedoch deutlich kleiner.
- Wie sichere ich eine Express-API ab?
- Grundlegende Sicherheitsmaßnahmen umfassen: Helmet.js für HTTP-Sicherheits-Header, Rate-Limiting mit express-rate-limit, Eingabevalidierung mit joi oder zod, HTTPS-Erzwingung und den Einsatz von JWT oder Session-basierter Authentifizierung. Das npm-Paket helmet sollte in keiner Express-App fehlen.