2012-08-28 23 views
54

Chcę wspierać podział na strony w moim interfejsie API REST.Ładunek odpowiedzi paginacji z RESTful API

Moja metoda API powinna zwrócić listę produktów JSON za pośrednictwem /products/index. Jednakże, istnieje potencjalnie tysiące produktów, a chcę, aby przejść przez nich, więc mój wniosek powinien wyglądać mniej więcej tak:

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

ale co moja odpowiedź JSON muszą wyglądać? Czy konsumenci API zwykle oczekują danych meta paginacji w odpowiedzi? Czy jest to tylko szereg produktów niezbędnych? Czemu?

Wygląda na to, że interfejs API serwisu Twitter zawiera metadane: https://dev.twitter.com/docs/api/1/get/lists/members (patrz przykładowe żądanie).

Z danych meta:

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

Tak szeroki wachlarz produktów (brak danych meta):

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

Odpowiedz

70

Interfejsy API ReSTful są używane głównie przez inne systemy, dlatego umieszczam dane stronicowania w nagłówkach odpowiedzi. Jednak niektórzy konsumenci API mogą nie mieć bezpośredniego dostępu do nagłówków odpowiedzi lub mogą budować UX na twoim interfejsie API, więc zapewnienie sposobu na odzyskanie (na żądanie) metadanych w odpowiedzi JSON jest plusem.

Uważam, że Państwa implementacja powinna zawierać domyślne metadane odczytywalne komputerowo, a na żądanie - metadane czytelne dla człowieka. Odczytane przez człowieka metadane mogą być zwracane przy każdym żądaniu, jeśli chcesz lub, najlepiej, na żądanie za pomocą parametru zapytania, takiego jak include=metadata lub include_metadata=true.

W twoim szczególnym scenariuszu chciałbym dołączyć identyfikator URI dla każdego produktu z zapisem. Ułatwia to konsumentowi API tworzenie linków do poszczególnych produktów. Postawiłbym również pewne rozsądne oczekiwania, zgodnie z limitami moich żądań stronicowania.Wdrażanie i dokumentowanie domyślnych ustawień rozmiaru strony jest akceptowalną praktyką. Na przykład GitHub's API ustawia domyślny rozmiar strony na 30 rekordów z maksymalnie 100, a także ustawia limit szybkości liczby zapytań o API. Jeśli twój interfejs API ma domyślny rozmiar strony, ciąg zapytania może po prostu określać indeks strony.

W scenariuszu czytelnej dla człowieka, kiedy przechodząc do /products?page=5&per_page=20&include=metadata, odpowiedź może być:

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

metadanych do odczytu maszynowego, dodałbym Link headers do odpowiedzi:

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 

(wartość nagłówka Link powinna być zakodowana)

... i prawdopodobnie niestandardowy total-count nagłówka odpowiedzi, jeśli więc wybrać:

total-count: 521 

Pozostałe dane przywoławcze ujawnione w metadanych człowieka-centric może być zbędny dla metadanych maszynowego-centric, jako nagłówki Link daj mi znać, na której stronie jestem na a liczba na stronę i mogę szybko pobrać liczbę rekordów w tablicy. Dlatego prawdopodobnie utworzyłbym tylko nagłówek dla całkowitej liczby. Zawsze możesz zmienić zdanie później i dodać więcej metadanych.

Na marginesie możesz zauważyć, że usunąłem /index z Twojego identyfikatora URI. Ogólnie przyjętą konwencją jest, aby twój punkt końcowy ReST ujawniał kolekcje. Mając /index na końcu błoto, które się nieznacznie podnosi.

To tylko kilka rzeczy, które lubię mieć podczas używania/tworzenia API. Mam nadzieję, że pomaga!

+0

per_page nie jest zgodna z konwencją page_size –

+1

'" page_count ": 20' i' {"last": "/ products? Page = 26 & per_page = 20"} '? –

+0

co by się stało, gdyby liczba produktów nagle wzrosła podczas pobierania wszystkich rekordów ze strony 1 do strony x? – MeV

23

Jako ktoś, kto napisał kilka bibliotek do spożywania usługi REST, Podam Ci perspektywa klienta, dlaczego myślę, że zawijanie wyniku w metadanych jest drogą:

  • Bez całkowitego zliczenia , w jaki sposób klient może wiedzieć, że nie otrzymał jeszcze wszystkiego, co istnieje i powinien kontynuować wywoływanie przez zestaw wyników? W interfejsie, który nie działał, patrz na następną stronę, w najgorszym przypadku może być reprezentowany jako link Następny/więcej, który nie pobierał jeszcze więcej danych.
  • Włączenie metadanych w odpowiedzi umożliwia klientowi śledzenie mniejszego stanu. Teraz nie muszę dopasowywać mojego żądania REST do odpowiedzi, ponieważ odpowiedź zawiera metadane niezbędne do odtworzenia stanu żądania (w tym przypadku kursor do zestawu danych).
  • Jeśli stan stanowi część odpowiedzi, mogę jednocześnie wysyłać wiele żądań do tego samego zestawu danych, a ja mogę obsługiwać żądania w dowolnej kolejności, w jakiej się pojawią, co niekoniecznie musi być zgodne z zamówieniem.

A propozycja: podobnie jak Twitter API, należy zastąpić numer strony prostym indeksem/kursorem. Powodem jest to, że interfejs API pozwala klientowi ustawić rozmiar strony na żądanie. Czy zwrócony numer_strony to liczba stron, o które klient prosił do tej pory, lub numer strony podanej ostatnio używanej wielkości strony (prawie na pewno później, ale dlaczego w ogóle nie unikać takiej dwuznaczności)?

+5

Do pierwszego pocisku, byłoby odpowiednim rozwiązaniem do pominięcia rel = następna link, jeśli nie było następnej strony? Na drugi punkt informacja jest nadal dostępna w odpowiedzi na klienta, ale nie znajduje się w treści odpowiedzi, ale znajduje się w nagłówkach. +1 do Twojego ostatniego akapitu. –

5

Polecam dodanie nagłówków do tego samego. Przenoszenie metadanych do nagłówków pomaga w pozbyciu się kopert, takich jak result, data lub records, a treść odpowiedzi zawiera tylko te dane, których potrzebujemy. Możesz użyć nagłówka Link, jeśli generujesz również łącza stronicowania.

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

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

Szczegółowe informacje znajdują się:

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

Dla pliku Swagger:

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