REST API design - 17 - HATEOAS : des liens dans tes réponses

Comprendre HATEOAS, le niveau 3 du modèle de Richardson, et savoir quand c'est utile ou excessif.

REST API design 18 / 25
  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

17 - HATEOAS : des liens dans tes réponses

Ce que tu vas apprendre

  • Ce que signifie HATEOAS et pourquoi ca existe
  • Le format HAL pour structurer les liens
  • Comment l'API GitHub utilise l'hypermedia
  • Pourquoi la plupart des APIs internes n'en ont pas besoin

Prerequisites

16 - Relations entre ressources


Tu connais ces sites ou chaque page contient des liens vers les pages suivantes. Tu cliques, tu decouvres. Tu n'as pas besoin de deviner l'URL. Le web fonctionne comme ca depuis 1991, et HATEOAS essaie de faire pareil pour les APIs.

Le dernier niveau de Richardson

Le modèle de maturite de Richardson definit 4 niveaux pour les APIs REST. Le niveau 3, le plus eleve, c'est HATEOAS : Hypermedia As The Engine Of Application State.

L'idee : chaque réponse de l'API contient des liens vers les actions possibles. Le client n'a pas besoin de construire les URLs lui-meme. Il suit les liens.

json{
  "id": "order-42",
  "status": "pending",
  "total": 8500,
  "_links": {
    "self": { "href": "/orders/order-42" },
    "cancel": { "href": "/orders/order-42/cancel", "method": "POST" },
    "payment": { "href": "/orders/order-42/pay", "method": "POST" },
    "customer": { "href": "/users/user-7" }
  }
}

Si la commande est deja payee, le lien payment disparaît. Le client sait ce qui est possible en lisant les liens, pas en codant en dur la logique métier.

Le format HAL

HAL (Hypertext Application Language) est le format le plus repandu pour HATEOAS. Il utilise deux propriétés reservees :

  • _links : les liens vers d'autres ressources
  • _embedded : des ressources imbriquees directement dans la réponse
json{
  "_links": {
    "self": { "href": "/orders?page=2" },
    "next": { "href": "/orders?page=3" },
    "prev": { "href": "/orders?page=1" }
  },
  "_embedded": {
    "orders": [
      {
        "id": "order-42",
        "total": 8500,
        "_links": {
          "self": { "href": "/orders/order-42" }
        }
      },
      {
        "id": "order-43",
        "total": 3200,
        "_links": {
          "self": { "href": "/orders/order-43" }
        }
      }
    ]
  },
  "totalItems": 156,
  "page": 2
}

Le Content-Type pour HAL est application/hal+json. D'autres formats existent : JSON:API, Siren, Hydra. Mais HAL reste le plus simple a implementer et a comprendre.

L'API GitHub comme exemple

GitHub est l'une des rares APIs publiques qui utilise HATEOAS serieusement. Chaque réponse contient des URLs completes :

json{
  "id": 1,
  "name": "mon-repo",
  "full_name": "nicolas/mon-repo",
  "html_url": "https://github.com/nicolas/mon-repo",
  "url": "https://api.github.com/repos/nicolas/mon-repo",
  "issues_url": "https://api.github.com/repos/nicolas/mon-repo/issues{/number}",
  "pulls_url": "https://api.github.com/repos/nicolas/mon-repo/pulls{/number}"
}

Le client n'a pas besoin de savoir que l'URL des issues est /repos/{owner}/{repo}/issues. Il la trouve dans la réponse. Si GitHub change la structure des URLs demain, les clients qui suivent les liens ne cassent pas.

Les URL templates ({/number}) suivent la RFC 6570. Le client remplace les variables par les valeurs reelles.

Quand HATEOAS est excessif

Je vais etre honnete : dans la majorite des projets sur lesquels j'ai travaille, HATEOAS n'apportait rien. Voici pourquoi.

APIs internes : quand le frontend et le backend sont développés par la meme équipe, tout le monde connaît les URLs. Ajouter des _links partout, c'est du bruit dans les réponses pour un gain nul.

SPAs avec routes hardcodees : ton application React a des routes figees. Elle ne va pas "découvrir" dynamiquement ou aller en suivant des liens API. Le frontend construit ses URLs avec un SDK ou des helpers.

Surcout non negligeable : générer les liens pour chaque réponse prend du temps cote serveur. Calculer les actions possibles selon l'état de la ressource et les permissions de l'utilisateur, ca veut dire exécuter de la logique métier dans le serializer.

Quand ca vaut le coup :

  • APIs publiques consommees par des tiers (ils ne connaissent pas ton code)
  • APIs avec des workflows complexes ou les actions possibles changent selon l'état
  • Quand tu veux pouvoir changer tes URLs sans casser les clients

Sur paltemps.fr, l'API est consommee uniquement par le frontend. Pas de HATEOAS. Les URLs sont dans un fichier de constantes partage. Simple et suffisant.

Implementer HATEOAS progressivement

Si tu decides que HATEOAS a du sens pour ton cas, commence petit :

typescriptfunction serializeOrder(order: Order, user: User) {
  const links: Record<string, { href: string }> = {
    self: { href: `/orders/${order.id}` }
  };

  if (order.status === "pending") {
    links.cancel = { href: `/orders/${order.id}/cancel` };
    links.pay = { href: `/orders/${order.id}/pay` };
  }

  if (order.status === "shipped") {
    links.track = { href: `/orders/${order.id}/tracking` };
  }

  if (user.role === "admin") {
    links.refund = { href: `/orders/${order.id}/refund` };
  }

  return { ...order, _links: links };
}

La logique conditionnelle des liens reflete exactement les transitions possibles de ta machine d'états. Si tu as deja une state machine propre, les liens HATEOAS en decoulent naturellement.

Self-describing APIs

HATEOAS fait partie d'un concept plus large : les APIs auto-descriptives. L'idee est qu'un client puisse explorer l'API sans documentation, juste en suivant les liens depuis le point d'entree.

bash# Point d'entree
curl https://api.example.com/

{
  "_links": {
    "users": { "href": "/users" },
    "orders": { "href": "/orders" },
    "products": { "href": "/products" },
    "docs": { "href": "/docs" }
  }
}

C'est elegant en theorie. En pratique, les développeurs lisent la documentation et utilisent des SDK. Personne ne "decouvre" une API en suivant des liens a la main. Mais pour de l'outillage automatise (crawlers, generateurs de SDK), ca peut avoir de la valeur.


Résumé

  • HATEOAS ajoute des liens dans les réponses pour guider le client vers les actions possibles
  • Le format HAL (_links, _embedded) est le plus courant
  • L'API GitHub est un bon exemple d'utilisation réelle
  • Pour les APIs internes et les SPAs, c'est souvent du bruit inutile
  • Si tu l'implementes, commence par les liens conditionnels lies aux transitions d'état

Article précédent : 16 - Relations entre ressources Article suivant : 18 - OpenAPI : spécifier ton API

Sources

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