Kodokon kodokon.com

Eingaben validieren und Fehler-Middleware

Validiere die Daten am Rand der API und zentralisiere die gesamte Fehlerbehandlung in einer einzigen Middleware mit vier Parametern.

9 Min. · 3 Fragen

Diese Lektion in Kodokon öffnen

Alle eingehenden Daten sind feindlich, bis das Gegenteil bewiesen ist: JSON-Rumpf, URL-Parameter, Header. Die Validierung gehört an den Rand der Anwendung - vor den Controller - damit die inneren Schichten auf garantierten Daten arbeiten. Unterscheide anschließend zwei Familien von Fehlern: operative Fehler (ungültige Eingabe, fehlende Ressource, Konflikt), die erwartet werden und in 4xx übersetzt werden, und Programmierfehler (Bugs), die auf Client-Seite ein undurchsichtiges 500 erzeugen müssen und auf Server-Seite einen vollständigen Stack-Trace.

JAVASCRIPT
export class HttpError extends Error {
  constructor(status, message, details = undefined) {
    super(message);
    this.status = status;
    this.details = details;
  }
}
Ein Fehler, der seinen HTTP-Status mitträgt: der Grundbaustein.

Eine Validierungs-Middleware fängt die Anfrage vor dem Controller ab. Die manuelle Version unten zeigt das Prinzip; in der Produktion liefert ein deklaratives Schema (zod ist zum Standard geworden) zusätzlich Typinferenz und strukturierte Meldungen. Der Kompromiss: eine Abhängigkeit und leichte Kosten zur Laufzeit, im Gegenzug für zentralisierte, kombinierbare Regeln, die man unmöglich vergessen kann.

JAVASCRIPT
import { HttpError } from './http-error.js';

export function validateUser(req, res, next) {
  const { email, name } = req.body ?? {};
  const errors = [];
  if (typeof email !== 'string' || !email.includes('@')) {
    errors.push('email: invalid format');
  }
  if (typeof name !== 'string' || name.trim().length < 2) {
    errors.push('name: 2 characters minimum');
  }
  if (errors.length > 0) {
    return next(new HttpError(400, 'Invalid body', errors));
  }
  next();
}
Hänge sie mit router.post('/', validateUser, controller.create) ein.

Express erkennt eine Fehler-Middleware an ihrer Signatur mit vier Parametern (err, req, res, next). Zuletzt registriert, nach allen Routen mit app.use(errorHandler), wird sie zum einzigen Fehlerausgang der API: ein einheitliches Antwortformat, Logging an einer einzigen Stelle, kein Durchsickern interner Informationen. Die Controller ihrerseits rufen einfach next(err) auf.

JAVASCRIPT
export function errorHandler(err, req, res, next) {
  if (res.headersSent) {
    return next(err);
  }
  const status = err.status ?? 500;
  const body = { error: err.message };
  if (err.details) {
    body.details = err.details;
  }
  if (status >= 500) {
    console.error(err);
    body.error = 'Internal server error';
  }
  res.status(status).json(body);
}
4xx transparent für den Client, 500 maskiert, aber protokolliert.

Wissenscheck

Stelle sicher, dass du die wichtigsten Punkte dieser Lektion behalten hast.

  1. Woran unterscheidet Express eine Fehler-Middleware von einer gewöhnlichen?
    • An ihrem Namen, der das Wort error enthalten muss
    • An ihrer Signatur mit vier Parametern (err, req, res, next)
    • An ihrer Position an erster Stelle in der Kette
    • An einem ausdrücklichen Aufruf von app.setErrorHandler
  2. Was ist die richtige HTTP-Antwort auf einen unerwarteten Programmierfehler?
    • Ein 500 mit Meldung und Stack, um die Diagnose zu erleichtern
    • Ein 400, um zu signalisieren, dass die Anfrage fehlgeschlagen ist
    • Ein 500 mit einer generischen Meldung, während der vollständige Fehler auf Server-Seite protokolliert wird
  3. Was passiert in Express 4, wenn ein async-Handler ohne try/catch abgelehnt wird?
    • Der Fehler erreicht die Fehler-Middleware trotzdem
    • Die Anfrage bleibt hängen: Die Ablehnung wird niemals an next weitergeleitet
    • Express gibt automatisch ein 400 zurück
    • Der Node-Prozess stoppt sofort