2008-11-20 12 views
69

Chciałbym uzyskać porady dotyczące projektowania interfejsu API REST, który umożliwi klientom efektywne dodawanie/usuwanie dużej liczby obiektów do kolekcji.Manipulacja zbiorową kolekcją za pomocą REST (RESTful) API

Za pośrednictwem interfejsu API klienci muszą mieć możliwość dodawania elementów do kolekcji i usuwania z niej elementów, a także manipulowania istniejącymi elementami. W wielu przypadkach klient będzie chciał dokonać zbiorczej aktualizacji kolekcji, np. dodając 1000 pozycji i usuwając 500 różnych przedmiotów. Wydaje się, że klient powinien móc to zrobić w pojedynczej transakcji z serwerem, zamiast wymagać 1000 oddzielnych żądań POST i 500 DELETE.

Czy ktoś ma jakieś informacje o najlepszych praktykach lub konwencjach do osiągnięcia tego?

Moje obecne myślenie jest takie, że powinno być możliwe naniesienie obiektu reprezentującego zmianę do identyfikatora URI kolekcji, ale wydaje się to sprzeczne z HTTP 1.1 RFC, co wydaje się sugerować, że dane wysyłane w żądaniu PUT powinny być interpretowane niezależnie z danych już obecnych w URI. Oznacza to, że klient musiałby wysłać za jednym razem pełny opis nowego stanu kolekcji, który może być znacznie większy niż zmiana, lub nawet być większy niż klient wiedziałby, kiedy złożyłby wniosek.

Oczywiście, byłbym szczęśliwy, gdyby odstąpić od RFC w razie potrzeby, ale wolałbym to zrobić w sposób konwencjonalny, jeśli taka konwencja istnieje.

+0

Czy kontrolujesz klientów za pomocą swojego API lub czy potrzebujesz obsługiwać istniejące produkty klienckie? Innymi słowy: Czy możesz zdefiniować semantykę jednostek żądań? – mkoeller

Odpowiedz

2

Powinieneś użyć AtomPub. Został specjalnie zaprojektowany do zarządzania kolekcjami za pośrednictwem protokołu HTTP. Może istnieć nawet implementacja wybranego języka.

+2

W rzeczywistości AtomPub definiuje tylko dodawanie pojedynczych elementów do kolekcji i usuwanie ich. Nie nazwałbym tego "specjalnie zaprojektowanego do zarządzania kolekcjami". –

2

W przypadku POST przynajmniej wydaje się, że powinieneś mieć możliwość POST do URL-a listy, a treść żądania zawiera listę nowych zasobów zamiast pojedynczego nowego zasobu.

1

O ile rozumiem, REST oznacza Reprezentacyjny transfer państwowy, więc należy przenieść stan z klienta na serwer.

Jeśli oznacza to zbyt dużo danych, to być może trzeba zmienić swoją reprezentację. Struktura collectChange działałaby z serią usunięć (według identyfikatora) i dodatków (z osadzonymi pełnymi reprezentacjami xml), POSTed do adresu URL interfejsu obsługi. Implementacja interfejsu może wybrać własną metodę usuwania i uzupełnień po stronie serwera.

Najczystszą wersją będzie najprawdopodobniej określenie elementów według adresu URL, a kolekcja zawiera serię adresów URL. Nowa kolekcja może być PUT po zmianach wprowadzonych przez klienta, po której następuje seria PUT dodawanych elementów, a być może seria usunięć, jeśli chcesz rzeczywiście usunąć elementy z serwera, a nie tylko usunąć je z tej listy.

0

Można wprowadzić meta-reprezentacji istniejących elementów kolekcji, które nie potrzebują ich cały stan przeniesiony, więc w jakimś abstrakcyjnym kodem swoją zmiana mogłaby wyglądać następująco:

{existing elements 1-100} 
{new element foo with values "bar", "baz"} 
{existing element 105} 
{new element foobar with values "bar", "foo"} 
{existing elements 110-200}

Dodawanie (i modyfikujące) elementów jest poprzez zdefiniowanie ich wartości, usunięcie elementów odbywa się poprzez nie wspomnienie o tym, że nowa kolekcja i elementy zmiany kolejności są wykonywane poprzez określenie nowego zamówienia (jeśli zamówienie jest w ogóle przechowywane).

W ten sposób można łatwo przedstawić całą nową kolekcję bez konieczności ponownego przesyłania całej zawartości. Korzystanie z nagłówka If-Unmodified-Since zapewnia, że ​​twoje wyobrażenie o treści rzeczywiście odpowiada idei serwerów (tak, aby przypadkowo nie usunąć elementów, o których po prostu nie wiedziałeś, kiedy wniosek został złożony).

+0

Jeśli dobrze rozumiem proponowany format aktualizacji, ma to tę wadę, że nie jest idempotentny, ponieważ odwołujesz się do elementów kolekcji w sposób względny (za pomocą indeksów) - jeśli aktualizacja jest "PUT" na serwerze dwukrotnie (być może przez wypadek), możesz skończyć z uszkodzoną kolekcją; na przykład element nr 105 będzie innym elementem za drugim razem niż za pierwszym razem; różne elementy 101-104 zostaną usunięte po raz drugi. – stakx

59

Być może zechcesz wymyślić zadanie zmiany jako zasób sam w sobie. Więc naprawdę chcesz wydać pojedynczy obiekt, który jest obiektem zbiorczej aktualizacji danych. Może ma nazwę, właściciela i duży obszar blobowy CSV, XML itp., Który musi zostać przeanalizowany i wykonany. W przypadku pliku CSV możesz również określić, jaki typ obiektów jest reprezentowany w danych CSV.

Wyświetlaj zadania, dodawaj zlecenie, przeglądaj status zlecenia, aktualizuj zlecenie (prawdopodobnie w celu jego uruchomienia/zatrzymania), usuń zlecenie (zatrzymaj je, jeśli działa) itd. Operacje te można łatwo mapować na Projekt interfejsu REST API.

Po zainstalowaniu tego można łatwo dodać różne typy danych, z którymi może poradzić sobie masowy aktualizator danych, a może nawet zmieszać je razem w tym samym zadaniu. Nie ma potrzeby powtarzania tego samego interfejsu API w całej aplikacji dla każdego rodzaju rzeczy, którą chcesz zaimportować.

To także bardzo łatwo nadaje się do realizacji zadania w tle. W takim przypadku prawdopodobnie chcesz dodać pola do poszczególnych obiektów zadań, które pozwalają klientowi API określić, w jaki sposób chcą być powiadamiani (adres URL, który chcą, abyś zrobił, gdy to zrobisz, lub wysłał im e-mail itp.) .

+2

To musi być zaznaczone jako odpowiedź! – HDave

+2

Dobra odpowiedź. Jeśli chcesz zastosować operację do dużego zestawu zasobów i wybierasz je za pomocą warunków filtrowania, możesz przekazać do zmiany zadanie obiekt z warunkami filtra. –

+2

Mimo, że rozsądne, aby uniknąć "rozmownych" DELETE, to wraca do mentalności RPC ... Być może jest to możliwe, aby pobrać kolekcję, usunąć wszystkie rzeczy, które chcesz usunąć, a następnie umieścić kolekcję (używając statusu odpowiedzi 409, aby wykryć rasę warunki z równoczesnymi modyfikatorami). Wykonalność tego zmniejsza się, jeśli GET jest stronicowany, w takim przypadku PATCH jest prawdopodobnie odpowiednią alternatywą. – delitescere

8

Tak, PUT tworzy/nadpisuje, ale nie aktualizuje częściowo.

Jeśli potrzebujesz częściowej semantyki aktualizacji, użyj PATCH. Zobacz http://greenbytes.de/tech/webdav/draft-dusseault-http-patch-14.html.

+0

To ma dla mnie największy sens. Jednak po kilkugodzinnym wyszukiwaniu w Internecie nie wydaje się to powszechnie obowiązującym punktem widzenia. Większość programistów wydaje się myśleć, że PATCH nie ma znaczenia w kolekcji. –

Powiązane problemy