it-swarm.com.de

Nutzdaten für Paginierungsantworten von einer RESTful-API

Ich möchte die Paginierung in meiner RESTful-API unterstützen.

Meine API-Methode sollte eine JSON-Produktliste über /products/index Zurückgeben. Es gibt jedoch möglicherweise Tausende von Produkten, und ich möchte sie durchblättern, sodass meine Anfrage ungefähr so ​​aussehen sollte:

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

Aber wie muss meine JSON-Antwort aussehen? Würden API-Konsumenten normalerweise Paginierungs-Metadaten in der Antwort erwarten? Oder ist nur eine Reihe von Produkten notwendig? Warum?

Die API von Twitter scheint Metadaten zu enthalten: https://dev.Twitter.com/docs/api/1/get/lists/members (siehe Beispielanforderung).

Mit Metadaten:

{
  "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"
    }
  ]
}

Nur eine Reihe von Produkten (keine Metadaten):

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

ReSTful-APIs werden hauptsächlich von anderen Systemen verwendet. Aus diesem Grund füge ich Paging-Daten in die Antwortheader ein. Einige API-Konsumenten haben jedoch möglicherweise keinen direkten Zugriff auf die Antwortheader oder erstellen möglicherweise eine UX über Ihre API. Daher ist es von Vorteil, (bei Bedarf) eine Möglichkeit zum Abrufen der Metadaten in der JSON-Antwort bereitzustellen.

Ich bin der Meinung, dass Ihre Implementierung standardmäßig maschinenlesbare Metadaten und auf Anfrage auch von Menschen lesbare Metadaten enthalten sollte. Die für den Menschen lesbaren Metadaten können bei jeder Anforderung zurückgegeben werden, wenn Sie möchten oder vorzugsweise bei Bedarf über einen Abfrageparameter wie include=metadata Oder include_metadata=true.

In Ihrem speziellen Szenario würde ich den URI für jedes Produkt in den Datensatz aufnehmen. Auf diese Weise kann der API-Konsument auf einfache Weise Links zu den einzelnen Produkten erstellen. Ich würde auch einige vernünftige Erwartungen in Bezug auf die Grenzen meiner Paging-Anforderungen festlegen. Das Implementieren und Dokumentieren von Standardeinstellungen für die Seitengröße ist eine akzeptable Vorgehensweise. Beispiel: GitHubs API legt die Standardseitengröße auf 30 Datensätze mit einem Maximum von 100 fest und legt ein Ratenlimit für die Häufigkeit fest, mit der Sie die API abfragen können. Wenn Ihre API eine Standardseitengröße hat, kann die Abfragezeichenfolge nur den Seitenindex angeben.

In dem für Menschen lesbaren Szenario könnte die Antwort bei der Navigation zu /products?page=5&per_page=20&include=metadata Lauten:

{
  "_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"
    }
  ]
}

Für maschinenlesbare Metadaten würde ich der Antwort Link-Header hinzufügen:

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

(der Link-Header-Wert sollte urlencodiert sein)

... und möglicherweise einen benutzerdefinierten total-count - Antwortheader, wenn Sie dies wünschen:

total-count: 521

Die anderen Auslagerungsdaten, die in den auf den Menschen bezogenen Metadaten angezeigt werden, könnten für maschinenzentrierte Metadaten überflüssig sein, da die Link-Header mich über meine aktuelle Seite und die Anzahl pro Seite informieren und ich die Anzahl der Datensätze im Array schnell abrufen kann . Daher würde ich wahrscheinlich nur einen Header für die Gesamtanzahl erstellen. Sie können Ihre Meinung später jederzeit ändern und weitere Metadaten hinzufügen.

Nebenbei bemerkt ihr vielleicht, dass ich /index Von eurer URI entfernt habe. Eine allgemein akzeptierte Konvention ist, dass Ihr ReST-Endpunkt Sammlungen verfügbar macht. Wenn Sie /index Am Ende haben, wird dies leicht durcheinander gebracht.

Dies sind nur ein paar Dinge, die ich beim Konsumieren/Erstellen einer API gerne habe. Hoffentlich hilft das!

88
codeprogression

Lassen Sie mich Ihnen als jemand, der mehrere Bibliotheken für den Konsum von REST= Services geschrieben hat, die Client-Perspektive geben, warum ich denke, das Ergebnis in Metadaten zu packen, ist der richtige Weg:

  • Woher kann der Client ohne die Gesamtzahl wissen, dass er noch nicht alles empfangen hat, was vorhanden ist, und das Blättern durch die Ergebnismenge fortsetzen? In einer Benutzeroberfläche, die nicht ausgeführt wurde, schauen Sie auf die nächste Seite. Im schlimmsten Fall wird dies möglicherweise als Next/More-Link dargestellt, über den keine weiteren Daten abgerufen wurden.
  • Durch das Einbeziehen von Metadaten in die Antwort kann der Client weniger Status verfolgen. Jetzt muss ich meine REST) -Anforderung nicht mehr mit der Antwort abgleichen, da die Antwort die Metadaten enthält, die zur Rekonstruktion des Anforderungsstatus erforderlich sind (in diesem Fall der Cursor in den Datensatz).
  • Wenn der Status Teil der Antwort ist, kann ich mehrere Anforderungen gleichzeitig in demselben Dataset ausführen und die Anforderungen in einer beliebigen Reihenfolge verarbeiten, in der sie zufällig eingehen. Dies muss nicht unbedingt die Reihenfolge sein, in der ich die Anforderungen gestellt habe.

Und ein Vorschlag: Wie bei der Twitter API sollten Sie die Seitennummer durch einen geraden Index/Cursor ersetzen. Der Grund dafür ist, dass die API es dem Client ermöglicht, die Seitengröße pro Anforderung festzulegen. Ist die zurückgegebene Seitennummer die Anzahl der Seiten, die der Client bisher angefordert hat, oder die Seitennummer, die der zuletzt verwendeten Seitengröße entspricht (mit ziemlicher Sicherheit die spätere, aber warum sollten Sie solche Mehrdeutigkeiten nicht ganz vermeiden)?

27
Majix

Ich würde empfehlen, Header für das gleiche hinzuzufügen. Das Verschieben von Metadaten in Header hilft dabei, Umschläge wie result, data oder records zu entfernen, und der Antworttext enthält nur die Daten, die wir benötigen. Sie können den Header Link verwenden, wenn Sie auch Paginierungslinks generieren.

    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"
      }
    ]

Einzelheiten finden Sie unter:

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

Für Swagger-Datei:

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

12
adnan kamili