Projektuję usługę sieci Web RESTful przy użyciu WebApi i zastanawiałem się, jakie odpowiedzi HTTP i treści odpowiedzi zostaną zwrócone podczas aktualizacji / tworzenia obiektów.
Na przykład mogę użyć metody POST, aby wysłać JSON do usługi sieci Web, a następnie utworzyć obiekt. Czy najlepiej jest ustawić status HTTP na utworzony (201) lub ok (200) i po prostu zwrócić komunikat, taki jak „Dodano nowego pracownika”, czy zwrócić obiekt, który został pierwotnie wysłany?
To samo dotyczy metody PUT. Którego stanu HTTP najlepiej użyć i czy muszę zwrócić utworzony obiekt, czy tylko wiadomość? Biorąc pod uwagę fakt, że użytkownik i tak wie, jaki obiekt próbuje utworzyć / zaktualizować.
jakieś pomysły?
Przykład:
Dodaj nowego pracownika:
POST /api/employee HTTP/1.1
Host: localhost:8000
Content-Type: application/json
{
"Employee": {
"Name" : "Joe Bloggs",
"Department" : "Finance"
}
}
Zaktualizuj istniejącego pracownika:
PUT /api/employee HTTP/1.1
Host: localhost:8000
Content-Type: application/json
{
"Employee": {
"Id" : 1
"Name" : "Joe Bloggs",
"Department" : "IT"
}
}
Odpowiedzi:
Odpowiedź z obiektem utworzonym / zaktualizowanym
HTTP/1.1 201 Created
Content-Length: 39
Content-Type: application/json; charset=utf-8
Date: Mon, 28 Mar 2016 14:32:39 GMT
{
"Employee": {
"Id" : 1
"Name" : "Joe Bloggs",
"Department" : "IT"
}
}
Odpowiedź z samą wiadomością:
HTTP/1.1 200 OK
Content-Length: 39
Content-Type: application/json; charset=utf-8
Date: Mon, 28 Mar 2016 14:32:39 GMT
{
"Message": "Employee updated"
}
Odpowiedź za pomocą samego kodu statusu:
HTTP/1.1 204 No Content
Content-Length: 39
Date: Mon, 28 Mar 2016 14:32:39 GMT
UPDATE/INSERT ... RETURNING
wariantu Postgresql dla SQL. Jest to bardzo przydatne, zwłaszcza, że utrzymuje przesyłanie nowych danych i żądanie zaktualizowanej wersji atomowej.Odpowiedzi:
Jak w większości rzeczy, to zależy. Kompromisem jest łatwość użycia w porównaniu z rozmiarem sieci. Klienci mogą zobaczyć bardzo dobrze utworzony zasób. Może zawierać pola wypełnione przez serwer, takie jak czas ostatniego utworzenia. Ponieważ wydaje się, że włączasz
id
zamiast używaćhateoas
, klienci prawdopodobnie będą chcieli zobaczyć identyfikator zasobu, który właśniePOST
edytowali.Jeśli nie uwzględnisz utworzonego zasobu, nie twórz arbitralnej wiadomości. Pola 2xx i Lokalizacja są wystarczającymi informacjami dla klientów, aby mieć pewność, że ich żądanie zostało poprawnie obsłużone.
źródło
Osobiście zawsze tylko wracam
200 OK
.Cytując twoje pytanie
Po co dodawać dodatkową przepustowość (za którą trzeba zapłacić), aby powiedzieć klientowi, co już wie?
źródło
200
/204 No Content
aby uniknąć mylenia jQuery i tym podobnych.@ iswinky Zawsze odsyłam ładunek w przypadku zarówno POST, jak i PUT.
W przypadku POST możesz utworzyć encję z wewnętrznym identyfikatorem lub UUID. Dlatego sensowne jest odesłanie ładunku.
Podobnie w przypadku PUT możesz zignorować niektóre pola użytkownika (powiedzmy niezmienne wartości) lub w przypadku PATCH dane mogą zostać zmienione również przez innych użytkowników.
Odesłanie danych w takim stanie, w jakim były przechowywane, jest zawsze dobrym pomysłem i zdecydowanie nie szkodzi. Jeśli dzwoniący nie potrzebuje tych zwracanych danych, nie będzie ich przetwarzał, ale po prostu zużyje kod statusu. W przeciwnym razie mogą wykorzystać te dane jako coś do aktualizacji interfejsu użytkownika.
Tylko w przypadku USUWANIA nie odesłałbym ładunku i zrobiłbym albo 200 z treścią odpowiedzi, albo 204 bez treści odpowiedzi.
Edycja: Dzięki niektórym komentarzom z dołu redaguję swoją odpowiedź. Nadal jestem przy sposobie projektowania moich interfejsów API i wysyłania odpowiedzi, ale myślę, że sensowne jest zakwalifikowanie niektórych moich myśli projektowych.
a) Kiedy mówię „odeślij ładunek”, tak naprawdę miałem na myśli odesłać dane zasobu, a nie ten sam ładunek, który przyszedł w żądaniu. Np .: jeśli wyślesz ładunek tworzenia, mogę w backendie utworzyć inne podmioty, takie jak UUID i (być może) znaczniki czasu, a nawet niektóre połączenia (graficzne). Odesłałbym to wszystko w odpowiedzi (nie tylko ładunek żądania, jaki jest - co jest bezcelowe).
b) Nie wysyłałbym odpowiedzi w przypadku, gdy ładowność jest bardzo duża. Omówiłem to w komentarzach, ale chciałbym ostrzec, że dołożę wszelkich starań, aby zaprojektować moje interfejsy API lub zasoby tak, aby nie musiały mieć bardzo dużych obciążeń. Próbowałbym podzielić zasoby na mniejsze i łatwe do zarządzania jednostki, tak aby każdy zasób był zdefiniowany przez 15-20 atrybutów JSON i nie był większy.
W przypadku, gdy obiekt jest bardzo duży lub obiekt nadrzędny jest aktualizowany, wówczas odsyłam zagnieżdżone struktury jako hrefs.
Najważniejsze jest to, że zdecydowanie spróbuję odesłać dane, które mają sens, aby konsument / interfejs użytkownika natychmiast przetworzyły i wykonały akcję atomową interfejsu API zamiast iść i pobrać 2-5 dodatkowych API tylko w celu zaktualizowania interfejsu użytkownika po tworzenie / aktualizacja danych.
Interfejsy API między serwerami mogą o tym myśleć inaczej. Skupiam się na interfejsach API, które zwiększają komfort użytkowania.
źródło
Odwołując się do standardów RFC łącza , powinieneś zwrócić 201 (utworzony) status po pomyślnym zapisaniu zasobu żądania za pomocą Post. W większości aplikacji identyfikator zasobu jest generowany przez sam serwer, dlatego dobrą praktyką jest zwrócenie identyfikatora utworzonego zasobu. Zwrócenie całego obiektu stanowi obciążenie dla żądania Post. Idealną praktyką jest zwrócenie adresu URL nowo utworzonego zasobu.
Na przykład możesz odwołać się do poniższego przykładu, który zapisuje obiekt pracownika w bazie danych i zwraca adres URL nowo utworzonego obiektu zasobu w odpowiedzi.
Ten punkt końcowy odpoczynku zwróci odpowiedź jako:
Status 201 - UTWORZONY
Lokalizacja nagłówka → http: // localhost: 8080 / workers / 1
źródło
Chciałbym uzależnić ładunek w treści zwrotnej od parametru HTTP.
Najczęściej najlepiej jest zwracać konsumentowi API jakąś treść, aby uniknąć niepotrzebnych podróży w obie strony (jeden z powodów istnienia GraphQL).
W rzeczywistości, ponieważ nasze aplikacje stają się bardziej obciążone danymi i rozproszone, staram się przestrzegać następujących wskazówek:
Moja wytyczna :
Za każdym razem, gdy istnieje przypadek użycia, który wymaga GET natychmiast po POST lub PUT, jest to przypadek, w którym najlepiej byłoby po prostu zwrócić coś w odpowiedzi POST / PUT.
Jak to się robi i jaki typ treści zwraca z PUT lub POST, jest to specyficzne dla aplikacji. Byłoby interesujące, gdyby aplikacja mogła sparametryzować typ „treści” w treści odpowiedzi (czy chcemy tylko lokalizacji nowego obiektu, niektórych pól, całego obiektu itp.)
Aplikacja może zdefiniować zestaw parametrów, które może otrzymać test POST / PUT w celu kontrolowania rodzaju „treści” zwracanej w treści odpowiedzi. Lub może zakodować jakieś zapytanie GraphQL jako parametr (widzę, że jest to przydatne, ale także staje się koszmarem konserwacyjnym).
Tak czy inaczej, wydaje mi się, że:
Więc 1) zrób to, ale 2) zachowaj prostotę.
Inną opcją, którą widziałem, są ludzie tworzący alternatywne punkty końcowe (powiedzmy, / klienci dla POST / PUT, którzy nic nie zwracają w treści i / customer_with_details dla POST / PUT dla / klientów, ale zwracają coś w treści odpowiedzi).
Unikałbym jednak takiego podejścia. Co dzieje się, gdy musisz zwrócić inny rodzaj treści? Jeden punkt końcowy na typ zawartości? Nie można skalować ani konserwować.
źródło