Sieben Anfänger-Aufgaben zum Programmieren mit Node.js und Express, gelöst und erklärt
Arbeiten Sie an sieben typischen Interviewaufgaben für Junior-Entwickler mit Node.js – von Express-Routen und Middleware über Fehlerbehandlung, Umkehrung von Zeichenketten sowie Erkennung von Duplikaten – und lernen Sie, jede davon zu erklären.
Bei Junior-Interviews zu Node.js und Express dreht sich selten um clevere Algorithmen. In der Regel erhält man kurze Aufgaben wie das Erstellen einer Route, das Schreiben eines Middleware-Funkts oder das Aufräumen eines Arrays, während der Interviewer beobachtet, wie man argumentiert und ob man erklären kann, warum der Code funktioniert. Die sieben untenstehenden Aufgaben decken die häufigsten Themen ab – jede mit einer funktionierenden Lösung, einer Erklärung der wichtigsten Zeilen sowie weiteren Punkten, die ein echtes Verständnis zeigen.
Aufgabe 1: Erstellen Sie eine einfache GET-Route
Eine klassische Aufwärmübung: „Erstellen Sie einen GET-Endpunkt unter /, der mit Hello World antwortet.“ Die Lösung erstellt eine Express-Anwendung, registriert einen Handler für den Root-Pfad und beginnt mit dem Zuhören auf einer Portnummer.
import express from "express";
const app = express();
app.get("/", (req, res) => {
res.status(200).send("Hello World");
});
app.listen(3000, () => {
console.log("Server running on port 3000");
});
Weil es import verwendet, benötigt das Projekt den Eintrag "type": "module" in package.json oder eine .mjs-Erweiterung.
Lese die Route Zeile für Zeile
Der Aufruf von app.get() registriert einen Handler, der nur auf GET-Anfragen reagiert:
app.get("/", (req, res) => {
Das erste Argument, /, ist der Pfad. Die Callback-Funktion erhält req, das die eingehende Anfrage beschreibt, sowie res, das zur Erstellung der Antwort verwendet wird.
Die Antwort selbst wird hier erzeugt:
res.status(200).send("Hello World");
status(200) setzt den Statuscode (200 ist der Standard, doch explizit zu sein macht die Codestruktur verständlicher), und send() schreibt den Inhalt und beendet die Antwort.
Zuletzt wird der Server gestartet:
app.listen(3000, () => {
Dies bindet die Anwendung an Port 3000; der Callback wird ausgelöst, sobald der Server Verbindungen annimmt. Reale Dienste lesen in der Regel den Port aus process.env.PORT.
Wie man es ausdrückt
"
app.get()registriert eine Route für GET-Anfragen. Wenn ein Client/aufruft, führt Express den Callback aus, der mit Status 200 und „Hello World“ antwortet."
Aufgabe 2: Schreiben Sie ein Middleware für die Protokollierung von Anfragen
Nächste Anweisung: „Erstellen Sie ein Middleware, das jede eingehende Anfrage protokolliert.“ Ein Middleware ist eine Funktion mit der Signatur (req, res, next). Diese gibt Methode und URL aus und übergibt anschließend die Kontrolle weiter; app.use() wendet sie auf alle nach ihr registrierten Routen an.
const logger = (req, res, next) => {
console.log(`${req.method} ${req.url}`);
next();
};
app.use(logger);
Jede Anfrage durchläuft die Kette in der Reihenfolge, bevor ein Routenhandler antwortet:
Client
↓
Request
↓
Logger Middleware
↓
Route Handler
↓
Response
Die wichtigste Zeile ist die letzte innerhalb der Funktion:
next();
next() teilt Express mit, dass dieser Schritt abgeschlossen ist und der nächste Middleware oder die nächste Route ausgeführt werden sollte. Wenn man das vergisst, hängt die Anfrage, bis der Client eine Zeitüberschreitung verursacht – das ist eine häufig gestellte Frage. Eine Alternative besteht darin, die Anfrage durch Senden einer Antwort zu beenden, wie es ein Authentifizierungs-Middleware tut, wenn ein fehlendes Token abgelehnt wird.
Wie man es ausdrückt
"Middleware erhält die Anfrage, die Antwort sowie
next. Es kann die Anfrage prüfen oder ändern und anschließend entweder antworten odernext()aufrufen, um die Kontrolle weiterzugeben."
Aufgabe 3: Asynchrone Aufgaben in einer Route verarbeiten
Echte Endpunkte warten auf Datenbanken und andere APIs, daher ist die Frage „Wie handhabt man eine asynchrone Operation in Express?“ zu erwarten. Eine solide Antwort ist ein async-Handler mit try/catch:
app.get("/users", async (req, res, next) => {
try {
const users = await getUsers();
res.status(200).json(users);
} catch (error) {
next(error);
}
});
Die entscheidende Zeile ist await:
const users = await getUsers();
Dies pausiert den Handler, bis getUsers() abgeschlossen ist, ohne andere Anfragen zu blockieren. Wenn die Promise abgelehnt wird, wird der catch-Block ausgeführt:
catch (error) {
next(error);
}
next(error) leitet den Fehler an das Fehlerbehandlungs-Middleware aus Aufgabe 5 weiter. Hinweis: Express 4 fängt abgelehnte Promises aus async-Handlern nicht auf, weshalb try/catch dort unerlässlich ist, während Express 5 sie automatisch weiterleitet. Weitere Informationen finden Sie unter Building production-grade error handling in Node.js apps.
Aufgabe 4: Skizzieren Sie die CRUD-Endpunkte
CRUD steht für Create, Read, Update und Delete – die vier grundlegenden Datenoperationen, wobei jede einer HTTP-Methode zugeordnet ist. Stubs für eine users-Ressource:
app.post("/users", (req, res) => {
res.status(201).send("User created");
});
app.get("/users", (req, res) => {
res.status(200).send("Users");
});
app.put("/users/:id", (req, res) => {
res.status(200).send("User updated");
});
app.delete("/users/:id", (req, res) => {
res.status(200).send("User deleted");
});
Die Erstellung gibt 201 Created zurück, und die Routen für einzelne Benutzer nehmen einen :id-Parameter entgegen, der aus req.params.id gelesen wird. Anstatt sich die Zeilen auswendig zu merken, sollten Sie wissen, was jede Methode bedeutet:
POST → Create
GET → Read
PUT → Update
DELETE → Delete
Seien Sie auf PUT versus PATCH vorbereitet: PUT ersetzt traditionell die gesamte Ressource, während PATCH eine teilweise Änderung vornimmt.
Wie man es ausdrückt
"CRUD umfasst die vier grundlegenden Datenoperationen. Im REST-Prinzip erstellt POST, liest GET, aktualisiert PUT oder PATCH und löscht DELETE."
Aufgabe 5: Fehlerbehandlung zentralisieren
Die Fehlerbehandlung folgt oft auf Aufgabe 3. Beginnen Sie mit einer fehlerhaften Route, die den Fehler weiterleitet:
app.get("/", (req, res, next) => {
try {
throw new Error("Something went wrong");
} catch (error) {
next(error);
}
});
Fügen Sie anschließend einen Fehlerhandler hinzu, der protokolliert und eine allgemeine 500-Antwort zurückgibt:
app.use((err, req, res, next) => {
console.error(err.message);
res.status(500).json({
message: "Internal Server Error"
});
});
Was diese Funktion besonders macht, ist ihre Signatur:
(err, req, res, next)
Express erkennt Fehlerhandler anhand ihrer vier deklarierten Parameter in der Reihenfolge err, req, res, next; sie werden nur ausgeführt, wenn ein Fehler übergeben wurde. Registrieren Sie den Handler nach Ihren Routen und vermeiden Sie es in der Produktion, err.message an die Clients zu senden. Der Ablauf:
Route
↓
Error occurs
↓
catch(error)
↓
next(error)
↓
Error middleware
↓
500 Response
Ist next() im Fehlerhandler erforderlich?
Nicht, wenn der Handler die Antwort selbst sendet:
app.use((err, req, res, next) => {
console.error(err.message);
res.status(500).send("Internal Server Error");
});
next muss dennoch deklariert werden, denn mit drei Parametern behandelt Express die Funktion als gewöhnliches Middleware.
Aufgabe 6: Eine Zeichenkette umkehren
Einige Fragen beziehen sich auf reines JavaScript: „Umkehren Sie den String hello.“ Die übliche One-Liner-Lösung verknüpft drei Methoden miteinander:
const str = "hello";
const reversed = str.split("").reverse().join("");
console.log(reversed);
Es wird ausgegeben:
olleh
Was jede Schritt tut
Durch Splitting erhalten wir die Zeichen:
str.split("")
Das Ergebnis ist ein Array:
["h", "e", "l", "l", "o"]
Anschließend wird die Reihenfolge vor Ort umgekehrt:
.reverse()
Dadurch entsteht:
["o", "l", "l", "e", "h"]
Schließlich werden die Zeichen ohne Trennzeichen zusammengefügt:
.join("")
So entsteht der umgekehrte String:
"olleh"
Eine gängige Variante: „Machen Sie es jetzt ohne reverse().“ Schleifen Sie vom letzten Index bis null abwärts:
const str = "hello";
let reversed = "";
for (let i = str.length - 1; i >= 0; i--) {
reversed += str[i];
}
console.log(reversed);
Sowohl Ansätze sind linear. Zu beachten: split("") und Indexierung arbeiten mit UTF-16-Code-Einheiten, wodurch Emojis in Teile zerlegt werden; [...str] hingegen teilt nach Codepunkten auf.
Aufgabe 7: Finden Sie Duplikate in einem Array
Noch ein Favorit: „Geben Sie Werte zurück, die mehrmals vorkommen.“ Gegeben:
const numbers = [1, 2, 3, 2, 4, 3, 5];
Das erwartete Ergebnis ist:
[2, 3]
Verwenden Sie zwei Set-Objekte, eines für bereits gesehene Werte und eines für bestätigte Duplikate:
const numbers = [1, 2, 3, 2, 4, 3, 5];
const seen = new Set();
const duplicates = new Set();
for (const number of numbers) {
if (seen.has(number)) {
duplicates.add(number);
} else {
seen.add(number);
}
}
console.log([...duplicates]);
Beim Ausführen wird folgendes protokolliert:
[2, 3]
Warum zwei Sets funktionieren
seen speichert jeden übergebenen Wert. Ein erster Auftreten wird dort hinzugefügt:
seen.add(number);
Ein Wiederholungsauftritt führt dazu, dass diese Überprüfung erfolgreich ist:
if (seen.has(number))
Dann gelangt der Wert in duplicates, und da ein Set Wiederholungen ignoriert, wird er nur einmal gemeldet. Suchvorgänge dauern nahezu konstante Zeit, sodass die Lösung linear und nicht durch quadratische verschachtelte Schleifen geprägt ist. Um Vorkommen zu zählen, verwenden Sie einen Map.
Gehen Sie vor dem Tippen Ihrer Lösung Ihren Ansatz durch
Die wichtigste Gewohnheit ist es, Ihren Plan vor dem Schreiben des Codes zu erklären, denn die Interviewer bewerten sowohl das Denkvermögen als auch die Ergebnisse. Für die Duplikatenaufgabe beginnen Sie mit etwas wie folgendem:
"Der Plan besteht aus einer Menge bereits gesehener Werte. Während der Schleife werden alle bereits vorhandenen Werte in eine zweite Menge mit Duplikaten gelegt, wodurch jede Einzelheit einzigartig bleibt."
Dann schreiben Sie den Code. Dadurch wird nachgewiesen, dass Sie verstehen und nicht nur auswendig lernen, und es ermöglicht dem Interviewer, Sie frühzeitig in die richtige Richtung zu lenken.
Vorbereitungs-Checkliste
Vor einem Interview zu Node.js oder Express sollten Sie sicherstellen, dass Sie folgende Dinge mühelos können:
- Routen definieren und die Rollen von
reqsowiereserläutern app.use()verwenden und eigene Middleware schreiben- Erläutern, was
next()bewirkt und was passiert, wenn es fehlt
async/await, try/catch und next(error)Set und Map für Abfragen und ZählungenVerwandte Literatur
- Node.js 26: Temporal API, Map Upserts und Undici 8 erläutert — Erklärt die wichtigsten Änderungen in Node.js 26 für den Backend-Bereich, einschließlich der stabilen Temporal API, nativer Map-Upsert-Methode, Leistungsverbesserungen durch Undici 8 sowie Änderungen, die vor einem Upgrade überprüft werden müssen.
- Node.js Streams erläutert: Behebung von Abstürzen aufgrund von Speicherüberlastung — Erfahren Sie, warum das Laden ganzer Dateien in den Speicher zu Abstürzen von Node.js-Servern führt und wie lesbare, schreibbare, duplex- sowie transformierende Streams dies durch Backpressure beheben.