Meilleures pratiques pour vos URLs, verbes HTTP et APIs
Par Delicious Insights • Publié le 5 juin 2013

Je suis tombé récemment, sur StackOverflow, sur une excellente réponse de Bob Aman à une ancienne question du style « comment faire des URLs qui respectent bien les conventions de REST » ?

En fait, Bob ne s'est pas à proprement parler limité à REST, mais a fournit toute une série de principes directeurs pour la mise en place tant d'URLs cohérentes que de choix de verbes HTTP cohérents pour aller avec, ainsi que certains préceptes importants pour le comportement du serveur et la réponse HTTP qu'il renvoie.

Tout ça date déjà pas mal (octobre 2009, mais souvenez-vous que Rails a popularisé REST—qui est aussi vieux que HTTP, en fait—avec sa version 2, en 2006) mais à en juger par la large dominance des URLs !@# pourries que je vois partout, ça mérite carrément d'être répété jusqu'à plus soif.

Au niveau des URLs elles-mêmes

  • Saymal : n’utilisez pas de paramètres URL (query string) pour altérer l'état côté serveur. Ils ont un autre rôle conceptuel (voir plus loin).
  • Saymal : ne mélangez pas la casse dans vos chemins, autant que possible. Préférez les minuscules.
  • Saymal : n’exposez pas des éléments dépendants de l'implémentation dans vos URLs (.php, .jsp, .aspx, .cfm, etc.)
  • Saymal : ne faites pas du RPC sur la seule base de vos URLs (Bob entend par là que vos URLs ne devraient normalement pas décrire une action mais une ressource, ce qui rejoint les principes de REST)

  • Saybien : limitez l'espace de noms de vos URLs autant que possible (soyez cohérents, basés sur ressources, minimalistes dans les suffixes, etc.)

  • Saybien : gardez vos segments de chemin raisonnablement courts
  • Saybien : choisissez entre /resource et /resource/ ; faites des redirections 301 depuis la variante que vous n’avez pas retenue.
  • Saybien : cantonnez vos paramètres de query string à de la sélection complémentaire au sein de la ressource ; typiquement pour la pagination, les recherches textuelles, etc.
  • Saybien : sortez des URLs les informations qui devraient figurer en en-tête ou corps de requête HTTP

Il y a naturellement quelques cas à la marge ; on en retrouvera la plupart (pour ceux que je considère légitimes, en tout cas) dans la discussion qui suit, laquelle porte cette fois-ci sur les verbes HTTP employés pour vos requêtes. À mon sens, l'URL et le verbe sont deux éléments indissociables dans les conventions que vous adoptez. Une requête HTTP exploite forcément l'un en conjonction avec l'autre.

Au niveau des verbes HTTP

Avant toute chose, il va de soi que ces règles sont conceptuelles et non strictement techniques : côté navigateur, vous simulerez en général le verbe hors-GET en faisant un POST avec un champ spécial (généralement _method), et côté serveur, suivant votre technologie, il faudra peut-être avoir recours au même subterfuge même si le client est capable d'émettre les véritables verbes…

  • Saymal : n’utilisez jamais GET pour modifier l'état côté serveur ; c'est une excellente manière de vous tirer une balle dès que le Googlebot passe vous dire bonjour.
  • Saymal : n'utilisez pas PUT à moins de mettre à jour l'intégralité de la ressource (pour le coup, je suis moyen d’accord ; il est vrai que PUT est sensé être idempotent et que le véritable verbe HTTP pour une mise à jour partielle est PATCH, mais si vous faites du PUT partiel c'est déjà nettement mieux qu'un bête POST, en vrai…)
  • Saymal : n'utilisez pas PUT si vous n'avez pas une utilisation légitime de GET sur la même URL
  • Saymal : n'utillisez pas POST pour récupérer une information à longue durée de vie ou en tout cas éminemment cachable par le client (les POST ne sont jamais cachés par les navigateurs, proxies, etc.)

  • Saybien : utilisez GET pour tout ce qui s'y prête (c'est cachable, bookmarkable, etc.).

  • Saybien : utilisez PATCH plutôt que PUT pour une mise à jour partielle (si tant est que votre couche serveur puisse le prendre en charge).
  • Saybien : utilisez POST plutôt que PUT ou PATCH si vous avez un doute
  • Saybien : préférez POST ou PATCH, suivant le cas, dès que vous faites un appel qui « sent le RPC » (déclenche une méthode modifiante de la ressource)
  • Saybien : préférez PUT si vous accédez à une ressource composite ou hiérarchique
  • Saybien : préférez DELETE pour toute suppression de la resource (qu'elle soit physique ou logique)
  • Saybien : utilisez GET pour des traitements de calcul, sauf si votre requête est trop large, auquel cas utilisez POST

Au niveau du comportement serveur et de sa réponse

  • Saymal : ne mettez pas vos méta-données (benchmarking, authentification, quotas API, unités API dépensées, etc.) dans le corps de la réponse mais dans son en-tête
  • Saymal : ne sortez pas vos méta-données dans une ressource à part, sauf si leur inclusion systématique entraîne un surpoids considérable.

  • Saybien : utilisez un code réponse approprié. Notamment :

    • 201 Created après avoir créé une ressource ; celle-ci doit toujours exister au moment où la réponse est envoyée.
    • 202 Accepted après avoir complété le traitement demandé ou lancé la création asynchrone d'une ressource (ex. PDF, Zip, rapport…).
    • 400 Bad Request quand les données transmises pour traitement sont pourries/invalides ; il peut s'agir d'une erreur de validation, par exemple. Réservez 500 pour les exceptions non attrapées.
    • 401 Unauthorized quand on accède à votre API sans avoir fourni l'en-tête Authorization (ou qu'il est invalide), à condition que vous attendiez bien cet en-tête comme mode d'autorisation.
    • 403 Forbidden quand le client accède à un endroit de votre API non autorisé pour lui
    • 405 Method Not Allowed quand le verbe HTTP employé n'est pas autorisé pour l'URL en cours
    • 413 Request Entity Too Large quand on vous envoie une requête trop grande par rapport à vos contraintes/exigences (idéalement traité par un middleware le plus en amont possible pour conserver les ressources serveur).
    • 418 I'm a teapot si on vous demande de faire du café alors que votre serveur tourne sur une théière réseau (si, ça existe, et y'en a plein d'autres utiles)
  • Saybien : tirez le meilleur parti possible des en-têtes de cache en réponse
    • ETag est pratique quand vous pouvez rapidement réduire une ressource à un hash (de façon fiable et identique à travers vos différents serveurs)
    • Last-Modified vous suggère que conserver quelque part le moment de dernière modification de chaque ressoure est plutôt une bonne idée…
    • Cache-Control et Expires devraient recevoir de votre part des valeurs pertinentes
  • Saybien : faites tout votre possible pour honorer les en-têtes de cache de la requête (If-None-Modified, If-Modified-Since)
  • Saybien : utilisez des redirections quand c’est approprié, mais pour des points d'accès de type API / Web Service, ça devrait être rarement le cas.

Allez maintenant, et que vos échanges HTTP soient propres !

Source : cette réponse de Bob Aman sur StackOverflow. Merci à lui !