Premier serveur HTTP en Node.js
Créer un serveur HTTP natif avec le module http, gérer les requêtes et réponses, et retourner du JSON — le point de départ de toute API Node.js.
🌐 Le module http natif
Node.js expose un module http intégré pour créer des serveurs HTTP sans dépendance externe. C'est le point de départ de toute API Node.js — avant d'utiliser Express, Fastify ou un autre framework.
import http from "node:http"
const PORT = 3000
const server = http.createServer((req, res) => {
res.writeHead(200, { "Content-Type": "text/plain" })
res.end("Bonjour depuis Node.js")
})
server.listen(PORT, () => {
console.log(`Serveur écoute sur http://localhost:${PORT}`)
})Le module http est intégré à Node.js — aucune installation npm n'est nécessaire. Pour les types TypeScript, installez @types/node.
📥 La requête (IncomingMessage)
La fonction callback reçoit deux arguments typés (avec @types/node) :
import http from "node:http"
import type { IncomingMessage, ServerResponse } from "node:http"
const server = http.createServer((req: IncomingMessage, res: ServerResponse) => {
// req.url — chemin de la requête (ex: "/api/ping")
// req.method — méthode HTTP (GET, POST, PUT, DELETE...)
// req.headers — en-têtes (nom en minuscules)
})Propriétés essentielles de IncomingMessage :
// req.url — chemin (ex: "/api/ping?name=test")
const path = req.url.split("?")[0] // "api/ping"
// req.method — GET, POST, PUT, DELETE, PATCH, OPTIONS...
if (req.method === "GET") { /* traiter la requête GET */ }
// req.headers — dictionnaire d'en-têtes (clés en minuscules)
const accept = req.headers.accept ?? "application/json"
const authorization = req.headers.authorization📤 La réponse (ServerResponse)
ServerResponse permet de construire la réponse :
// writeHead(code, headers) — en-têtes et code HTTP
res.writeHead(200, {
"Content-Type": "application/json",
"X-Custom-Header": "valeur"
})
// end(body) — termine la réponse (le corps peut être une string ou un Buffer)
res.end(JSON.stringify({ message: "Bonjour" }))writeHead + end
La réponse doit toujours se terminer avec res.end(). Sans end(), le client reste en attente indéfiniment (timeout côté client).
🏗️ Serveur HTTP complet — exemple typé
Voici un serveur qui expose une route /api/ping et renvoie du JSON :
import http from "node:http"
import type { IncomingMessage, ServerResponse } from "node:http"
const PORT = 3000
const server = http.createServer((req: IncomingMessage, res: ServerResponse) => {
// === Route /api/ping (GET) ===
if (req.url === "/api/ping" && req.method === "GET") {
res.writeHead(200, { "Content-Type": "application/json" })
res.end(JSON.stringify({
status: "ok",
timestamp: Date.now(),
}))
return
}
// === Route inconnue ===
res.writeHead(404, { "Content-Type": "application/json" })
res.end(JSON.stringify({ error: "Not found" }))
})
server.listen(PORT, () => {
console.log(`Serveur écoute sur http://localhost:${PORT}`)
})🎯 Codes HTTP courants
| Code | Signification | Quand l'utiliser |
|---|---|---|
200 | OK | Requête traitée avec succès |
201 | Created | Ressource créée (POST) |
204 | No Content | Succès sans corps (DELETE souvent) |
400 | Bad Request | Requête mal formée ou paramètres invalides |
401 | Unauthorized | Non authentifié |
403 | Forbidden | Non autorisé (authentifié mais pas les droits) |
404 | Not Found | Route ou ressource inexistante |
405 | Method Not Allowed | Méthode non gérée sur la route |
500 | Internal Server Error | Erreur serveur inattendue |
import http from "node:http"
import type { IncomingMessage, ServerResponse } from "node:http"
const server = http.createServer((req: IncomingMessage, res: ServerResponse) => {
const url = req.url
const method = req.method
// Route GET /api/tasks
if (url === "/api/tasks" && method === "GET") {
res.writeHead(200, { "Content-Type": "application/json" })
res.end(JSON.stringify({ tasks: [] }))
return
}
// Route POST /api/tasks
if (url === "/api/tasks" && method === "POST") {
res.writeHead(201, { "Content-Type": "application/json" })
res.end(JSON.stringify({ id: 1, title: "Nouvelle tâche" }))
return
}
// Méthode non gérée sur une route connue
if (url === "/api/tasks" && method !== "GET" && method !== "POST") {
res.writeHead(405, { "Content-Type": "application/json" })
res.end(JSON.stringify({ error: `Method ${method} not allowed` }))
return
}
// Route inconnue
res.writeHead(404, { "Content-Type": "application/json" })
res.end(JSON.stringify({ error: "Not found" }))
})📝 Parser le corps d'une requête POST
Pour lire le corps d'une requête POST (ex: JSON envoyé par le client), il faut accumuler les chunks :
import http from "node:http"
import type { IncomingMessage, ServerResponse } from "node:http"
function lireCorps(req: IncomingMessage): Promise<string> {
return new Promise((resolve, reject) => {
let corps = ""
req.on("data", (chunk: string) => { corps += chunk })
req.on("end", () => resolve(corps))
req.on("error", (err) => reject(err))
})
}
const server = http.createServer(async (req: IncomingMessage, res: ServerResponse) => {
if (req.url === "/api/tasks" && req.method === "POST") {
try {
const corps = await lireCorps(req)
const data = JSON.parse(corps) as { title: string }
res.writeHead(201, { "Content-Type": "application/json" })
res.end(JSON.stringify({ id: 1, ...data }))
} catch {
res.writeHead(400, { "Content-Type": "application/json" })
res.end(JSON.stringify({ error: "Corps invalide" }))
}
return
}
res.writeHead(404, { "Content-Type": "application/json" })
res.end(JSON.stringify({ error: "Not found" }))
})Express simplifie tout ça
Dans la séance 5, vous migrerez ce serveur vers Express. Express gère automatiquement le parsing du corps (express.json()), le routage déclaratif (app.get, app.post), et la gestion d'erreurs centralisée. Mais comprendre le module http natif fait la différence quand un middleware ne fait pas ce qu'on attend.
Quiz du chapitre
Node.js
Terminez le quiz du chapitre pour le marquer comme complété.
Écosystème npm et package.json
Le registre npm, le manifeste package.json, les dépendances et les scripts — le cœur de l'écosystème Node.js.
Atelier — Construire un serveur HTTP pas à pas
Partir d'un serveur minimal et l'améliorer progressivement : routes multiples, parsing de corps, fichiers statiques, gestion d'erreurs.