TW3 — Technologies du Web 3

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

CodeSignificationQuand l'utiliser
200OKRequête traitée avec succès
201CreatedRessource créée (POST)
204No ContentSuccès sans corps (DELETE souvent)
400Bad RequestRequête mal formée ou paramètres invalides
401UnauthorizedNon authentifié
403ForbiddenNon autorisé (authentifié mais pas les droits)
404Not FoundRoute ou ressource inexistante
405Method Not AllowedMéthode non gérée sur la route
500Internal Server ErrorErreur 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

3 questions
0 / 3 répondue0%
  1. 1Quel module intégré de Node.js permet de créer un serveur HTTP sans installation supplémentaire ?
  2. 2Quel code HTTP renvoie-t-on quand une route est connue mais que la méthode HTTP n'est pas gérée ?
  3. 3Pourquoi appelle-t-on toujours res.end() après res.writeHead() ?
Répondez à toutes les questions pour valider.

Node.js

Terminez le quiz du chapitre pour le marquer comme complété.

Tableau de bord

On this page