Ich kenne was, was Du nicht kennst: media-typer

the next big thing  –  0 Kommentare

REST-Dienste müssen gelegentlich auf den Content-Type-Header einer Anfrage reagieren. Doch wie überprüft man diesen verlässlich? Was auf den ersten Blick trivial erscheint, ist bei näherem Hinsehen komplexer als gedacht. Das Modul media-typer schafft Abhilfe.

In einem REST-Dienst auf den Content-Type-Header einer Anfrage zu reagieren, erscheint zunächst trivial: Vermeintlich genügt es, den entsprechenden Header aus dem req-Objekt auszulesen und mit einem fest vorgegebenen Wert zu vergleichen:

let contentType = req.headers['content-type'];
if (contentType === 'image/svg') {
// ...
}

Die Realität sieht allerdings anders aus, denn der Header enthält potenziell mehr Daten, als vom Entwickler erwartet. Dazu zählt beispielsweise die Angabe eines Suffixes, was unter anderem bei Bildern regelmäßig zum Einsatz kommt.

Suffixe und Parameter

Für ein SVG lautet der Content-Type daher häufig nicht wie erwartet image/svg, sondern image/svg+xml. Beides kann aber für einen REST-Dienst gültig sein und sollte gleich behandelt werden. Durch die zusätzliche Angabe steigt die Komplexität der Abfrage:

let contentType = req.headers['content-type'];
if (contentType === 'image/svg' || contentType === 'image/svg+xml') {
// ...
}

"Ich kenne was, was Du nicht kennst"

... ist eine gemeinsame Serie von Golo Roden und Philip Ackermann, in der die beiden regelmäßig Module für JavaScript und Node.js vorstellen.

Wenn mehrere Suffixe möglich sind, wird der Vergleich rasch unübersichtlich, sodass sich der Einsatz eines regulären Ausdrucks anbietet.

Noch schwieriger wird es, wenn der Header zusätzlich Parameter wie ein Encoding enthält. Dann muss der Header am passenden Trennzeichen gespalten werden: image/svg+xml; charset=utf-8. Erschwerend kommt hinzu, dass sich nicht nur ein, sondern prinzipiell beliebig viele Parameter angeben lassen. Außerdem sind die Bezeichner nicht schreibungsabhängig, sodass sich keine Annahmen bezüglich Groß- und Kleinschreibung treffen lassen.

Das Modul media-typer

Um all das zu vereinfachen bietet sich der Einsatz des Moduls media-typer an, das das Analysieren des Headers übernimmt und die Daten als Objekt zurückgibt. Die Installation erfolgt auf dem üblichen Weg mit Hilfe von npm in den lokalen Kontext der Anwendung:

$ npm install media-typer

Danach kann es wie gewohnt mit Hilfe der require-Funktion eingebunden werden:

const typer = require('media-typer');

Anschließend lässt sich an dem Objekt typer die parse-Funktion mit einer zu analysierenden Zeichenkette aufrufen:

let type = typer.parse('image/svg+xml; charset=utf-8');

Alternativ kann man das req-Objekt auch direkt angeben. Das Modul extrahiert den Content-Type-Header dann eigenständig. Daher ist der Aufruf von

let type = typer.parse(req);

nichts anderes als die Kurzform für den Aufruf:

let type = typer.parse(req.headers['content-type']);

Das Ergebnis verarbeiten

Das Ergebnis ist in allen Fällen das gleiche: Die Funktion gibt ein Objekt zurück, das in den Eigenschaften type und subtype den eigentlichen Typ beschreibt. Die Eigenschaft suffix enthält ein gegebenenfalls angegebenes Suffix. Die Eigenschaft parameters hingegen ist ein Objekt, das die angegebenen Parameter enthält.

Dabei wandelt das Modul auch sämtliche Bezeichner in Kleinschreibung um, sodass sich auf sie auf einheitliche Art zugreifen lässt:

console.log(type);
// => {
// type: 'image',
// subtype: 'svg',
// suffix: 'xml',
// parameters: {
// charset: 'utf-8'
// }
// }

Zu guter Letzt kennt das Modul auch noch die Funktion format, die den umgekehrten Weg beschreitet und das Objekt wieder in eine Zeichenkette umwandelt.

tl;dr: Das Analysieren des Content-Type-Headers ist aufwendiger als häufig vermutet. Das Modul media-typer übernimmt die lästige Arbeit und liefert die gewünschten Informationen als Objekt zurück.