Une API qui renvoie des listes doit limiter le nombre d’éléments transmis dans chaque réponse. Sans pagination, une requête peut consommer inutilement des ressources, augmenter la latence et compliquer l’intégration du service. Le choix ne se limite pas à une question de syntaxe : le mécanisme détermine aussi ce que les consommateurs voient lorsque les données changent, la façon dont ils parcourent les résultats et les garanties qu’ils peuvent attendre.
Les deux approches les plus courantes sont la pagination par offset, qui indique combien d’enregistrements ignorer, et la pagination par curseur, qui utilise une référence pour poursuivre à partir d’une position. Le choix dépend des usages et des garanties nécessaires : aucune stratégie n’est la meilleure dans tous les cas.
Les garanties à définir pour une réponse paginée

Avant de choisir un mécanisme, définissez le contrat de la collection. Décidez au minimum de la taille maximale des pages, de l’ordre des éléments, de la manière de demander la page suivante et du comportement lorsqu’il n’y a plus de résultats. Précisez également comment la pagination se combine avec les filtres et le tri.
L’ordre doit être déterministe. Un tri fondé uniquement sur une date, par exemple, peut laisser plusieurs enregistrements à égalité. Sans règle pour départager ces résultats, des requêtes successives peuvent placer des éléments à des positions différentes. Ajouter un critère unique, tel que l’identifiant de l’enregistrement, permet d’établir une séquence sans ambiguïté.
Une réponse peut contenir les éléments et une référence pour poursuivre, ainsi que des métadonnées comme la taille effective de la page. Tous les clients n’ont pas besoin de connaître le nombre total de résultats : le calcul peut être coûteux et, dans une collection qui évolue souvent, le total peut rapidement devenir obsolète. Ne fournissez que les informations utiles au cas d’usage.
Pagination par offset : accéder facilement à une position
Avec un offset, le client indique une limite et le nombre d’éléments à ignorer. Une demande conceptuelle pourrait être : « renvoyer 20 éléments à partir du 40e enregistrement ». Ce modèle est simple à expliquer et convient aux interfaces qui affichent des pages numérotées, permettent de rejoindre une page précise ou offrent un accès direct à des résultats plus éloignés dans la liste.
Son principal avantage est la simplicité du contrat. Les clients peuvent créer des liens vers des pages et les équipes peuvent raisonner en plages de résultats. Cette approche peut suffire pour les collections de petite taille ou relativement stables, notamment lorsque la navigation directe est une exigence réelle.
La limite apparaît lorsque les données changent entre deux requêtes. Si un élément est inséré au début de la liste après le chargement de la première page, l’offset utilisé pour demander la suivante peut renvoyer un enregistrement déjà consulté. Si un élément est supprimé avant la position demandée, un résultat encore inédit peut être omis. L’offset ne garantit pas à lui seul une vue cohérente d’une collection dynamique.
Par ailleurs, demander une position très éloignée peut obliger le système à parcourir ou à ignorer de nombreux enregistrements, selon la base de données, la requête et les index. Le comportement varie d’un système à l’autre : mesurez-le avec des requêtes représentatives. Si les pages profondes deviennent lentes, limitez les sauts ou évaluez une autre stratégie.
Pagination par curseur : poursuivre à partir d’une position
Avec la pagination par curseur, la réponse fournit une référence que le client transmet pour obtenir la tranche suivante. Le curseur représente une position dans un ordre ; il peut, par exemple, s’appuyer sur la valeur de tri et sur un identifiant qui départage les égalités. Le client n’a pas besoin de connaître la structure interne de cette référence.
Pour obtenir un comportement prévisible, la requête doit conserver le même ordre d’une demande à l’autre. Un curseur fondé sur une date nécessite un critère supplémentaire si plusieurs lignes partagent cette date. Les modifications concurrentes peuvent toujours influer sur les pages suivantes, mais une stratégie reposant sur la position ordonnée évite généralement les décalages provoqués par le saut d’un nombre de lignes. Cela ne constitue pas nécessairement un instantané immuable : une telle garantie demande un comportement supplémentaire, qui doit être conçu et documenté.
Le curseur doit rester opaque pour le consommateur. Il peut encoder des données de position, mais encoder ne signifie ni chiffrer ni protéger. N’incluez pas d’informations sensibles sans protection adaptée et vérifiez que le curseur correspond à la requête, à l’utilisateur et au contexte d’autorisation concernés. Définissez également sa durée de validité et la réponse renvoyée lorsqu’il ne peut plus être utilisé.
Cette approche convient aux parcours séquentiels, aux flux, aux grands catalogues et aux traitements qui avancent dans les résultats sans sauter vers une page arbitraire. En contrepartie, la navigation directe est plus complexe et le format, la validation et la compatibilité des curseurs demandent une attention particulière.
Critères pratiques pour faire son choix
Évaluez l’expérience attendue par les consommateurs et les caractéristiques de l’ensemble de données. Voici quelques repères :
- Choisissez l’offset si les pages numérotées ou les sauts directs sont importants, si la collection est limitée ou si les changements pendant la navigation ont un impact acceptable.
- Choisissez le curseur si les résultats sont parcourus séquentiellement, si l’ensemble peut devenir très volumineux ou si les insertions et suppressions rendent les décalages indésirables.
- Comparez les coûts réels avec des requêtes et des tailles représentatives. La stratégie, les index, les filtres et la base de données influent sur les performances.
- Tenez compte du mode d’intégration : une exportation par lots peut nécessiter une progression fiable, tandis qu’une interface d’administration peut privilégier l’accès à une page précise.
Ne mélangez pas les deux modèles sans en préciser le périmètre. Proposer un offset pour certaines requêtes et un curseur pour d’autres peut être pertinent, à condition de documenter clairement le contrat de chaque collection. Ne présentez pas non plus le curseur comme une garantie de cohérence totale si la conception ne conserve qu’une position et que la collection continue d’évoluer.
Filtres, tri et limites : le contrat dans son ensemble
Le curseur et la page suivante doivent correspondre aux mêmes filtres et au même ordre que ceux de la première réponse. Si le client modifie ces paramètres, il doit commencer un nouveau parcours plutôt que réutiliser une référence liée à une autre requête. L’API peut refuser cette combinaison ou produire des curseurs contenant le contexte nécessaire à sa validation.
Documentez une taille de page par défaut et un maximum par requête. Une limite évite les réponses disproportionnées, mais doit rester cohérente avec les usages prévus et ne pas obliger le client à multiplier les appels. Précisez le comportement lorsque la valeur est absente, invalide ou supérieure au maximum : appliquer une limite ou renvoyer une erreur sont deux possibilités, à condition de conserver un comportement cohérent.
Le tri demandé par l’utilisateur nécessite lui aussi des règles claires. N’acceptez que les champs et les directions autorisés, prévoyez un critère déterministe pour départager les égalités et empêchez qu’un changement de tri soit associé par inadvertance à un ancien curseur. Ces précautions réduisent les doublons, les omissions et les requêtes difficiles à optimiser.
Migrer sans interrompre les intégrations existantes
Si une API expose déjà un offset, modifier la réponse ou supprimer des paramètres peut casser des applications et des intégrations. Avant toute migration, identifiez les clients, leurs usages, les pages profondes et les erreurs observées. Si la télémétrie est insuffisante, instrumentez les requêtes pour savoir quels paramètres sont utilisés, dans le respect des politiques de confidentialité et de conservation applicables.
- Définissez le nouveau contrat : ordre, filtres, taille maximale, format opaque du curseur et comportement en cas de curseur invalide.
- Assurez explicitement la compatibilité : introduisez, par exemple, une nouvelle route ou un nouveau paramètre, ou prévoyez une transition documentée qui conserve temporairement l’ancien mécanisme.
- Testez les changements concurrents, les égalités dans le tri, la dernière page, les filtres modifiés ainsi que les curseurs mal formés ou réutilisés hors contexte.
- Suivez l’adoption et les performances avant de supprimer l’ancienne option. Annoncez les changements et fournissez des consignes de mise à jour aux consommateurs.
Évitez qu’une réponse change silencieusement de sens selon le client ou que le serveur interprète un paramètre ambigu de deux façons. La compatibilité doit pouvoir être vérifiée ; les dates ou conditions de retrait doivent être documentées, jamais supposées.
Liste de vérification pour prendre une décision

- Les consommateurs doivent-ils accéder directement à une page numérotée ?
- Les données changent-elles pendant leur parcours, et quel est l’impact des répétitions ou des omissions ?
- L’ordre est-il déterministe et comporte-t-il un critère unique pour départager les égalités ?
- Les requêtes profondes et les tailles de page réalistes ont-elles été mesurées ?
- Les filtres, les limites, les erreurs et la réutilisation des curseurs sont-ils définis ?
- Une stratégie de compatibilité existe-t-elle, ainsi qu’un moyen de suivre l’adoption ?
Si l’accès direct aux pages est essentiel et que la collection reste maîtrisable, l’offset peut être un choix raisonnable. Si le parcours est principalement séquentiel et que le volume ou les changements rendent les décalages fragiles, le curseur est souvent plus adapté. Définissez d’abord les garanties nécessaires, puis choisissez le mécanisme : l’API répondra ainsi aux besoins réels de ses consommateurs et pourra évoluer sans surprise.
