Normalisation des retours JSON

TL; DR:

{
  items: [1, 2, ...otherUsersIds],
  users: {
    '1' : {
      content: {
        id: 1,
        name: 'Popol',
        organization_id: 1
      },
      avatarURL: '//img.ur/trololol.png'
    },
    ...otherUsers
  },
  organisations: {
    '1': {
      content: {
        id: 1,
        name: 'Popol inc.',
        owner_id: 1
      }
    }
  }
}
  

Cela fait un moment que je souhaite écrire ce billet, notamment à l'usage de référence pour les personnes à qui je parle de ma façon de designer les retours de mes APIs.

Si vous n'avez pas ragequit ce blog à la suite de son TL;DR, laissez moi vous expliquer pourquoi j'ai fini par utiliser cette structure pour mes retours JSON.

Normalisation

À ne pas confondre avec standardisation ou structuration. Ici, j'entends le terme normalisation comme on l'entendrait dans une base de donnée relationnelle mais pour un seul retour JSON.

Souvent, dans de nombreuses API, la décision est prise d'embarquer des ressources relatives à une ressource retournée par un point d'API. Par exemple, un GET /users/:userId pourrait retourner aussi l'organisation ou les organisations de ce dernier.

Certains diront que c'est le moment où il faut envisager d'utiliser GraphQL. Je ne serais pas aussi catégorique. Je ne vois pas de souci majeur à ajuster légèrement un retour pour apporter des informations supplémentaires. Après tout les principes RESTful autorisent plusieurs représentations d'une même ressource donc pourquoi s'en priver ?

En revanche, l'erreur à ne pas commettre est d'embarquer les ressources liées directement comme propriété de ce dernier. En effet, ceci a pour effet que si deux utilisateurs ont la même organisation, celle-ci se retrouve en double dans le retour JSON.

Vous comprenez donc certainement mieux le TL;DR de ce billet. La structure que j'utilise dans mes JSON permet d'éviter ce problème.

Vous remarquerez également que la liste des items d'une collection n'est pas directement dans la collection, mais seuls leurs identifiants apparaissent. La raison est que cela permet d'avoir des collections qui se répètent. Par exemple, un point d'API GET /usersQueue pourrait lister plusieurs fois le même utilisateur car ce dernier aurait réservé plusieurs slots dans une file d'attente. Autre avantage, le user propriétaire de l'organisation de mon exemple peut être retrouvé facilement dans le JSON.

Vous pourriez me rétorquer “Et pourquoi pas JSON Reference ?”. Pour rappel, JSON reference est une spécification qui vise à pouvoir utiliser des références à d'autres valeurs du JSON lui-même afin de pouvoir créer des références circulaires.

Trois raisons m'en empêchent :

< Blog