REST API design - 05 - Body, headers et le diable dans les détails

JSON body, Content-Type, Accept, headers custom et clés d'idempotence pour des API solides.

  1. 01 REST API design - 00 - Pourquoi le design de ton API change tout
  2. 02 REST API design - 01 - Les principes REST que personne ne lit
  3. 03 REST API design - 02 - Des URLs qui ont du sens
  4. 04 REST API design - 03 - Les méthodes HTTP, pour de vrai
  5. 05 REST API design - 04 - Les codes de statut HTTP qu'il faut connaître
  6. 06 REST API design - 05 - Body, headers et le diable dans les détails
  7. 07 REST API design - 06 - La pagination, ou comment ne pas tuer ta base
  8. 08 REST API design - 07 - Filtrage et tri sans prise de tête
  9. 09 REST API design - 08 - La validation avec Zod, gardien de ton API
  10. 10 REST API design - 09 - Erreurs : un format que tes clients vont adorer
  11. 11 REST API design - 10 - Authentification : JWT, API keys et OAuth2
  12. 12 REST API design - 11 - Versioning : quand et comment faire évoluer ton API
  13. 13 REST API design - 12 - CORS : comprendre et debugger les erreurs cross-origin
  14. 14 REST API design - 13 - Rate limiting : protéger ton API sans frustrer tes clients
  15. 15 REST API design - 14 - Caching : les bonnes réponses sont celles qu'on n'envoie pas
  16. 16 REST API design - 15 - Upload de fichiers : multipart, signed URLs et streaming
  17. 17 REST API design - 16 - Relations entre ressources : embarquer, lier ou les deux
  18. 18 REST API design - 17 - HATEOAS : des liens dans tes réponses
  19. 19 REST API design - 18 - OpenAPI : le contrat entre ton API et le monde
  20. 20 REST API design - 19 - Documentation : une API non documentee est une API inutile
  21. 21 REST API design - 20 - Testing : tester ton API sans devenir fou
  22. 22 REST API design - 21 - Webhooks : quand c'est ton API qui appelle
  23. 23 REST API design - 22 - Performance : quand chaque milliseconde compte
  24. 24 REST API design - 23 - Sécurité : les attaques que tu vas subir (et comment t'en protéger)
  25. 25 REST API design - 24 - Glossaire : tous les termes REST API en un seul endroit

05 - Body, headers et le diable dans les détails

Ce que tu vas apprendre

  • Comment structurer un body JSON propre
  • Les headers HTTP standards que ton API doit utiliser
  • Quand et comment créer des headers custom
  • Les clés d'idempotence et pourquoi elles sauvent des vies

Prerequisites


Le header oublie qui a coûte cher

Un collegue avait déployé une API de paiement. Tout fonctionnait en dev. En prod, les requêtes echouaient mysterieusement. Apres deux heures de debug, le problème : le reverse proxy ajoutait Content-Encoding: gzip mais le serveur Node ne decompressait pas. Le body arrivait comme du charabia. Un header manquant dans la config Express, et 500 transactions bloquees.

Les headers ne sont pas un détail. Ils sont le système nerveux de HTTP.

Le body JSON

Structure de requête

Garde tes bodies plats autant que possible. L'imbrication profonde complique la validation et la documentation.

typescript// Bon : structure plate et claire
const createUserBody = {
  name: "Alice Martin",
  email: "alice@example.com",
  role: "editor",
};

// Acceptable : un niveau d'imbrication pour grouper
const createOrderBody = {
  items: [
    { productId: "prod_123", quantity: 2 },
    { productId: "prod_456", quantity: 1 },
  ],
  shippingAddress: {
    street: "12 rue de Rivoli",
    city: "Paris",
    postalCode: "75001",
  },
};

// Mauvais : imbrication excessive
const badBody = {
  data: {
    attributes: {
      user: {
        profile: {
          name: "Alice",
        },
      },
    },
  },
};

Structure de réponse

Je recommande un format coherent pour toutes tes réponses :

typescript// Ressource unique
{
  "id": 42,
  "name": "Alice",
  "email": "alice@example.com",
  "createdAt": "2026-03-29T10:30:00Z"
}

// Collection
{
  "data": [
    {"id": 42, "name": "Alice"},
    {"id": 43, "name": "Bob"}
  ],
  "meta": {
    "total": 156,
    "page": 1,
    "limit": 20
  }
}

Pour les dates, utilise toujours ISO 8601 avec le fuseau horaire : 2026-03-29T10:30:00Z. Pas de timestamps Unix, pas de formats locaux.

Les headers standards indispensables

Content-Type

Dit au serveur quel format tu envoies. Dit au client quel format il recoit.

http# Requete
POST /api/users HTTP/1.1
Content-Type: application/json

# Reponse
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

Si ton API n'accepte que du JSON, refuse proprement les autres formats :

typescriptapp.use((req, res, next) => {
  if (
    req.method !== "GET" &&
    req.method !== "DELETE" &&
    !req.is("application/json")
  ) {
    return res.status(415).json({
      error: "Unsupported Media Type. Use application/json.",
    });
  }
  next();
});

Accept

Le client indique quel format de réponse il préféré.

httpGET /api/users/42 HTTP/1.1
Accept: application/json

En theorie, ton API pourrait renvoyer du JSON ou du XML selon le header Accept. En pratique, la plupart des API modernes ne supportent que JSON, et c'est tres bien comme ca.

Authorization

Le header standard pour l'authentification.

httpGET /api/users/me HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

N'invente pas un header custom pour ca. Authorization est compris par tous les outils, proxies et middlewares du monde.

Cache-Control et ETag

Pour le caching des réponses GET.

httpHTTP/1.1 200 OK
Cache-Control: public, max-age=3600
ETag: "v1-abc123"

Location

Pointe vers la ressource créée apres un POST.

httpHTTP/1.1 201 Created
Location: /api/users/43

Les headers custom

Quand tu as besoin d'un header spécifique a ton application, prefixe-le avec un nom de projet (le prefixe X- est déprécié mais encore tres courant).

http# Cle d'idempotence
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000

# Rate limiting info
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 42
X-RateLimit-Reset: 1711720800

# Request ID pour le tracing
X-Request-Id: req_abc123def456

Les clés d'idempotence

C'est le mecanisme le plus sous-estime en design d'API. Le problème : un client envoie un POST pour créer une commande. Le réseau coupe. Le client ne sait pas si la commande a ete créée ou non. Il renvoie la requête. Sans clé d'idempotence, tu as deux commandes.

typescriptrouter.post("/api/orders", async (req, res) => {
  const idempotencyKey = req.headers["idempotency-key"];

  if (!idempotencyKey) {
    return res.status(400).json({
      error: "Idempotency-Key header is required",
    });
  }

  // Verifier si cette cle a deja ete utilisee
  const existing = await idempotencyStore.get(idempotencyKey);

  if (existing) {
    // Renvoyer la meme reponse que la premiere fois
    return res.status(existing.statusCode).json(existing.body);
  }

  // Creer la commande
  const order = await orderService.create(req.body);

  // Stocker la reponse associee a cette cle
  await idempotencyStore.set(idempotencyKey, {
    statusCode: 201,
    body: order,
  });

  res.status(201).json(order);
});

Stripe utilise ce pattern pour toutes ses API de paiement. Si ca marche pour des milliards de dollars de transactions, ca marchera pour ton app.

La duree de vie d'une clé d'idempotence est généralement de 24 a 48 heures. Apres ca, la meme clé peut etre reutilisee.

Tu trouveras plus d'exemples de patterns de headers sur paltemps.fr.

Résumé

  • JSON avec structure plate, dates en ISO 8601, format coherent entre les endpoints
  • Content-Type, Accept, Authorization, Location : les headers standards non negociables
  • Refuse les Content-Type non supportes avec un 415
  • Les clés d'idempotence protegent les POST contre les doubles envois
  • Les headers custom pour le rate limiting et le tracing ameliorent l'observabilité

Precedent : Les codes de statut HTTP | Suivant : La pagination

Sources

Réservez un audit gratuit de 30 minutes. Je vous montre concrètement ce qu'on peut automatiser.