TL;DR: La pagination c’est bien™, le faire avec des paramètres limit/offset c’est mal™.
C’est très simple à expliquer : Si les données sont mises à jour entre deux requêtes d’une même pagination, au mieux vous manquez des données et en visualisez d’autres en double, au pire vous corrompez tous vos calculs.
Hypermedia
La solution magique c’est que vos API retournent un nombre limité de résultats avec des liens dans les entêtes, probablement un rel=next pour les données suivantes et/ou un rel=prev pour les données précédentes. Le client n’a qu’à suivre les liens.
En pratique
OK, je triche parce que je n’explique rien, alors je vais prendre un exemple : Un hypothétique client Twitter sur une hypothétique API Twitter (je m’autorise donc à ne pas préciser ce qui se fait sur les API actuelles).
Lorsque Twitter vous retourne les 100 derniers tweets de votre timeline avec les identifiants 3245 à 3566, il peut vous renvoyer deux liens dans les entêtes :
- Un rel=last qui mène en fait vers l’exacte requête que vous avez faite mais avec en plus un paramètre since_id=3566. Quand vous voudrez rafraichir votre timeline, il vous suffira de suivre le lien. Il vous retournera les nouveaux messages jusqu’au 3566 non compris, mais jamais ceux que vous avez déjà reçu.
- Un rel=prev qui mène vers l’exacte même requête que vous avez faite, mais avec en plus un paramètre max_id=3245. Quand vous voudrez aller chercher les messages plus anciens, il vous suffira de suivre le lien.
Si vous suivez un rel=prev après avoir suivi un rel=last vous finirez avec un lien qui contient et un since_id et un max_id, vous assurant de combler les trous que vous avez dans votre timeline, sans jamais renvoyer un message en double ni en oublier.
Si vous souhaitez faire une synchronisation complète, il suffit de stocker tous les liens rel=prev que vous recevez dans une liste, et d’aller les suivre un à un à la fréquence que vous souhaitez. Vous pouvez avoir un autre fil d’exécution en parallèle qui suit le rel=last de temps en temps (il n’y en aura qu’un seul à la fois, vous en aurez un nouveau à chaque fois que vous suivez le précédent).
Bon, dans la vraie vie vous aurez généralement un rel=next (messages juste suivants) plutôt qu’un rel=last (derniers messages), mais Twitter est particuliers : Ça va si vite qu’en général la priorité est d’avoir les derniers messages à date, quitte à générer des trous dans la timeline qui seront comblés plus tard.
Twitter est aussi facile parce qu’on trie toujours pas date, et que l’identifiant unique de chaque message est toujours ordonné lui aussi. Ailleurs on utilisera peut être la date de dernière modification comme pivot pour gérer la pagination. L’important est que le critère de tri soit cohérent avec la donnée utilisée comme pivot
Laisser un commentaire