Des liens qui dépendent de l'état

C'est là que HATEOAS devient vraiment utile : les liens ne décrivent pas seulement les ressources liées, mais aussi ce qu'on a le droit de faire maintenant.

La vie d'une commande

pending ──(30 s)──▶ preparing ──(2 min)──▶ ready ──▶ served
   │
   └──▶ cancelled   (uniquement tant qu'elle est pending)

Juste après la commande :

{
  "id": 42,
  "status": "pending",
  "cocktail": "Segfault Sunrise",
  "_links": {
    "self":     {"href": "/v1/orders/42"},
    "cancel":   {"href": "/v1/orders/42", "method": "DELETE"},
    "cocktail": {"href": "/v1/cocktails/3"}
  }
}

30 secondes plus tard, le barman a commencé. Même requête :

{
  "id": 42,
  "status": "preparing",
  "cocktail": "Segfault Sunrise",
  "_links": {
    "self":     {"href": "/v1/orders/42"},
    "cocktail": {"href": "/v1/cocktails/3"}
  }
}

Le lien cancel a disparu. Le serveur ne dit pas « tu ne peux plus annuler parce que le statut est preparing » : il ne propose simplement plus l'action.

Faites l'essai : commandez un cocktail et interrogez la commande toutes les 10 secondes avec curl. Regardez le lien disparaître en direct.

Côté client : suivre les liens, pas les règles

Sans HATEOAS, le client doit connaître la règle métier :

# ❌ La règle est dupliquée dans le client
if order["status"] == "pending":
    show_cancel_button()

Le jour où le bar autorise l'annulation pendant la préparation, il faut mettre à jour toutes les applications : web, mobile, caisse… Avec HATEOAS, le client se contente de regarder si le lien existe :

order = requests.get(urljoin(BASE, "/v1/orders/" + str(order_id)), headers=headers).json()

cancel = order["_links"].get("cancel")
if cancel:
    print("Annulation possible")
    requests.request(cancel["method"], urljoin(BASE, cancel["href"]), headers=headers)
else:
    print("Trop tard, le shaker tourne déjà")

La règle n'existe qu'à un seul endroit : le serveur. Il peut la changer, tous les clients suivent.

Ça marche aussi pour les droits

Les liens peuvent dépendre de qui demande, pas seulement de l'état :

Masquer un lien n'est pas une protection : le serveur doit toujours vérifier l'état et les droits quand l'action arrive. Un DELETE envoyé à la main sur une commande en préparation doit toujours répondre 409.


Revision #4
Created 2 October 2026 20:00:59 by Thibaud FRICHET
Updated 13 October 2026 19:13:39 by Thibaud FRICHET