web-dev-qa-db-fra.com

Charge utile de réponse de pagination à partir d'une API RESTful

Je souhaite prendre en charge la pagination dans mon API RESTful.

Ma méthode API doit renvoyer une liste JSON du produit via /products/index. Cependant, il existe potentiellement des milliers de produits, et je veux les feuilleter, alors ma demande devrait ressembler à ceci:

/products/index?page_number=5&page_size=20

Mais à quoi ma réponse JSON doit-elle ressembler? Les utilisateurs d'API s'attendent-ils généralement à des métadonnées de pagination dans la réponse? Ou seulement une gamme de produits est-elle nécessaire? Pourquoi?

Il semble que l’API de Twitter inclut des métadonnées: https://dev.Twitter.com/docs/api/1/get/lists/members (voir Exemple de demande).

Avec métadonnées:

{
  "page_number": 5,
  "page_size": 20,
  "total_record_count": 521,
  "records": [
    {
      "id": 1,
      "name": "Widget #1"
    },
    {
      "id": 2,
      "name": "Widget #2"
    },
    {
      "id": 3,
      "name": "Widget #3"
    }
  ]
}

Juste un tableau de produits (pas de métadonnées):

[
  {
    "id": 1,
    "name": "Widget #1"
  },
  {
    "id": 2,
    "name": "Widget #2"
  },
  {
    "id": 3,
    "name": "Widget #3"
  }
]
69
Chad Johnson

Les API ReSTful sont principalement utilisées par d'autres systèmes. C'est pourquoi j'ai placé les données de pagination dans les en-têtes de réponse. Cependant, certains consommateurs d'API peuvent ne pas avoir un accès direct aux en-têtes de réponse ou créer une UX sur votre API, ce qui permet de récupérer (à la demande) les métadonnées de la réponse JSON.

Je pense que votre implémentation devrait inclure des métadonnées lisibles par machine par défaut et des métadonnées lisibles par l'homme, le cas échéant. Les métadonnées lisibles par l'homme peuvent être renvoyées avec chaque demande si vous le souhaitez ou, de préférence, à la demande via un paramètre de requête, tel que include=metadata ou include_metadata=true.

Dans votre scénario particulier, j'inclurais l'URI de chaque produit avec l'enregistrement. Cela permet au consommateur d'API de créer facilement des liens vers les produits individuels. Je voudrais également définir des attentes raisonnables en fonction des limites de mes demandes de pagination. L'implémentation et la documentation des paramètres par défaut pour la taille de la page est une pratique acceptable. Par exemple, API de GitHub définit la taille de page par défaut sur 30 enregistrements avec un maximum de 100, et définit une limite de débit sur le nombre de fois que vous pouvez interroger l'API. Si votre API a une taille de page par défaut, la chaîne de requête peut simplement spécifier l'index de page.

Dans le scénario lisible par l'homme, lors de la navigation vers /products?page=5&per_page=20&include=metadata, la réponse pourrait être:

{
  "_metadata": 
  {
      "page": 5,
      "per_page": 20,
      "page_count": 20,
      "total_count": 521,
      "Links": [
        {"self": "/products?page=5&per_page=20"},
        {"first": "/products?page=0&per_page=20"},
        {"previous": "/products?page=4&per_page=20"},
        {"next": "/products?page=6&per_page=20"},
        {"last": "/products?page=26&per_page=20"},
      ]
  },
  "records": [
    {
      "id": 1,
      "name": "Widget #1",
      "uri": "/products/1"
    },
    {
      "id": 2,
      "name": "Widget #2",
      "uri": "/products/2"
    },
    {
      "id": 3,
      "name": "Widget #3",
      "uri": "/products/3"
    }
  ]
}

Pour les métadonnées lisibles par machine, j'ajouterais en-têtes de lien à la réponse:

Link: </products?page=5&perPage=20>;rel=self,</products?page=0&perPage=20>;rel=first,</products?page=4&perPage=20>;rel=previous,</products?page=6&perPage=20>;rel=next,</products?page=26&perPage=20>;rel=last

(la valeur de l'en-tête du lien doit être codée en url)

... et éventuellement une coutume total-count en-tête de réponse, si vous le souhaitez:

total-count: 521

Les autres données de pagination révélées dans les métadonnées centrées sur l'homme pourraient être superflues pour les métadonnées centrées sur la machine, car les en-têtes de lien me permettent de savoir sur quelle page je suis et le nombre par page, et je peux rapidement récupérer le nombre d'enregistrements dans le tableau. . Par conséquent, je ne créerais probablement qu'un en-tête pour le compte total. Vous pouvez toujours changer d'avis plus tard et ajouter plus de métadonnées.

En passant, vous remarquerez peut-être que j'ai enlevé /index à partir de votre URI. Une convention généralement acceptée consiste à faire en sorte que votre point de terminaison ReST expose des collections. Ayant /index à la fin, il y a une légère hausse.

Ce ne sont là que quelques aspects que j’aime avoir lors de la création/création d’une API. J'espère que ça t'as aidé!

88
codeprogression

En tant que personne ayant écrit plusieurs bibliothèques pour la consommation de services REST), permettez-moi de vous donner la perspective du client sur la raison pour laquelle je pense que le fait d'encapsuler le résultat dans des métadonnées est la voie à suivre:

  • Sans le nombre total, comment le client peut-il savoir qu'il n'a pas encore reçu tout ce qu'il a et qu'il devrait continuer à paginer à travers le jeu de résultats? Dans une interface utilisateur non performante, attendez-vous à la page suivante, dans le pire des cas, cela pourrait être représenté par un lien Suivant/Plus qui ne récupère plus de données.
  • L'inclusion de métadonnées dans la réponse permet au client de suivre moins d'état. Maintenant, je n'ai pas besoin de faire correspondre ma demande REST), car la réponse contient les métadonnées nécessaires pour reconstruire l'état de la demande (dans ce cas, le curseur dans l'ensemble de données).
  • Si l'état fait partie de la réponse, je peux effectuer plusieurs demandes simultanément dans le même jeu de données et gérer les demandes dans n'importe quel ordre d'arrivée, ce qui n'est pas nécessairement l'ordre dans lequel j'ai effectué les demandes.

Et une suggestion: comme le Twitter API , vous devriez remplacer le numéro de page par un index/un curseur droit. La raison en est que l'API permet au client de définir la taille de la page par demande. Le numéro de page renvoyé correspond-il au nombre de pages demandées jusqu'ici par le client ou au numéro de la page correspondant à la dernière taille de page utilisée (presque certainement la dernière, mais pourquoi ne pas éviter complètement cette ambiguïté)?

27
Majix

Je recommanderais d'ajouter des en-têtes pour les mêmes. Déplacer les métadonnées vers les en-têtes aide à se débarrasser des enveloppes telles que result, data ou records et le corps de la réponse ne contient que les données dont nous avons besoin. Vous pouvez utiliser Link header si vous générez également des liens de pagination.

    HTTP/1.1 200
    Pagination-Count: 100
    Pagination-Page: 5
    Pagination-Limit: 20
    Content-Type: application/json

    [
      {
        "id": 10,
        "name": "shirt",
        "color": "red",
        "price": "$23"
      },
      {
        "id": 11,
        "name": "shirt",
        "color": "blue",
        "price": "$25"
      }
    ]

Pour plus de détails, consultez:

https://github.com/adnan-kamili/rest-api-response-format

Pour le fichier swagger:

https://github.com/adnan-kamili/swagger-response-template

12
adnan kamili