Czy przez REST można zwrócić zawartość po POST?

88

Używam RESTlet i utworzyłem zasób. Obsługuję POST metodą nadpisywania acceptRepresentation.

Klient powinien wysłać mi jakieś dane, a następnie przechowuję je w DB, ustawiam odpowiedź na 201 (SUCCESS_CREATED) i muszę zwrócić klientowi niektóre dane, ale typ zwrotu acceptRepresentationto void.

W moim przypadku muszę zwrócić jakiś identyfikator, aby klient miał dostęp do tego zasobu.

Na przykład, jeśli mam zasób z adresem URL /resourcei klient wysyła żądanie POST, dodaję nowy wiersz w DB i jego adres powinien być /resource/{id}. Muszę wysłać {id}.

czy robię coś źle? Czy zasady REST pozwalają coś zwrócić po POST? Jeśli tak, jak mogę to zrobić, a jeśli nie, jaki jest sposób rozwiązania tej sytuacji?

del-boy
źródło
Zobacz odpowiedź Thoma, jak ustawić treść odpowiedzi z poziomu acceptRepresentation ().
Avi Flax

Odpowiedzi:

96

REST mówi tylko, że powinieneś dostosować się do jednolitego interfejsu. Innymi słowy, mówi, że powinieneś zrobić to, co powinien zrobić POST, zgodnie ze specyfikacją HTTP . Oto cytat z tej specyfikacji, który jest istotny:

Jeśli zasób został utworzony na serwerze pochodzenia, odpowiedź POWINNA być 201 (utworzona) i zawierać jednostkę, która opisuje stan żądania i odwołuje się do nowego zasobu, oraz nagłówek lokalizacji (patrz sekcja 14.30).

Jak widać z tego, masz dwa miejsca, w których możesz wskazać klientowi, gdzie znajduje się nowo utworzony zasób. Nagłówek lokalizacji powinien mieć adres URL wskazujący na nowy zasób, a także można zwrócić jednostkę ze szczegółami.

Nie jestem pewien, jaka jest różnica między zastępowaniem funkcji acceptRepresentation () a przesłanianiem post (), ale ten przykład pokazuje, jak zwrócić odpowiedź z POST.

Darrel Miller
źródło
2
@ del-boy: Zobacz odpowiedź Thoma, jak ustawić treść odpowiedzi z poziomu acceptRepresentation ().
Avi Flax
1
Cytat ze specyfikacji HTTP nie zabrania odpowiedzi, jeśli Request and Response messages MAY transfer an entity if not otherwise restricted by the request method or response status code. An entity consists of entity-header fields and an entity-body, although some responses will only include the entity-headers.
zajrzysz do
@MikeF Nie miałem zamiaru wnioskować, że treść odpowiedzi jest niedozwolona. Część specyfikacji, którą zacytowałem, konkretnie mówi „i zawiera jednostkę”. Powinienem był wyrazić się jaśniej w moim tekście.
Darrel Miller
16

Zrezygnowałbym z wysłania czegokolwiek w treści odpowiedzi. Wystarczy ustawić lokalizację: na (pełny) adres URL nowo utworzonego zasobu.

Twój opis sugeruje, że jest to dokładnie ta semantyka, którą:

  1. OPUBLIKUJ rzecz, aby ją utworzyć
  2. Odpowiedz wystarczająco, by wiedzieć dwie rzeczy:
    1. Że stworzenie się wydarzyło (201)
    2. Gdzie znaleźć nową rzecz (nagłówek Lokalizacja)

Wszystko inne jest zbyteczne.

cdent
źródło
Nie chodzi o to, że Wikipedia jest zawsze dobrym źródłem, ale to również twierdzi , że „[...] Aby zapewnić informacje o lokalizacji nowo utworzonego zasobu. W takiej sytuacji nagłówek Location należy przesłać z kodem stanu HTTP 201 lub 202 ”.
Arjan
1
POST może wykonywać logikę, która tworzy jeden lub więcej zasobów. Wynik przetwarzania może być potrzebny klientowi. Zatem zwrócenie go w odpowiedzi pozwala uniknąć konieczności wykonywania jednego lub więcej wywołań GET do interfejsu API. Dane utworzone / zmienione metodą POST mogą nie być (i często nie są) zbędne dla klienta.
Paulo Merson
10

Dwa różne pytania:

Czy wzorzec aplikacji REST obsługuje zwracanie danych w POST?

Nie sądzę, by REST wyraźnie tego zabronił, ale preferowane traktowanie jest określone w odpowiedzi Darrela.

Czy struktura RESTlet umożliwia zwracanie danych w POST?

Tak, mimo że zwraca void, w klasie rozszerzającej Resource masz pełny dostęp do obiektu obiektu Response za pośrednictwem metody getResponse (). Możesz więc wywołać metodę getResponse (). SetEntity () z dowolnymi danymi.

Thom
źródło
6

Wypisz go w dowolnym formacie. To może być:

<success>
    <id>5483</id>
</success>

Lub:

{ "type": "success", "id": 5483 }

To zależy od tego, co zwykle robisz. Jeśli nie oczekują danych, powinni je po prostu zignorować, ale każdy klient, który chce właściwie sobie z nimi poradzić, powinien to zrobić.

Samir Talwar
źródło
Ok, mam dwa możliwe formaty (html i xml). Wiem, jak obsłużyć żądany format, ale nie wiem, jak dodać dane do odpowiedzi. reprezentuje metodę zwraca Reprezentację, więc po prostu zwracam, co chcę, ale acceptRepresentation jest metodą void, więc nie mogę zwrócić żadnych danych ...
del-boy
1

Jeśli odpowiesz 201 Created za pomocą treści encji, a nie przekierowania Location, dobrym pomysłem jest dołączenie nagłówka Content-Location wskazującego na zasób, który jest reprezentowany w odpowiedzi.

Pozwoli to uniknąć potencjalnego zamieszania - w którym klient mógłby (słusznie) założyć, że jednostka odpowiedzi faktycznie reprezentuje nowy stan „twórcy”, a nie utworzony zasób.

> POST /collection
> ..new item..

< 201 Created
< Location: /collection/1354
< Content-Location: /collection/1354
< <div class="item">This is the new item that was created</div>
Mikrofon
źródło
3
Myślę, że Content-Location ma inny cel. Specyfikacja HTTP mówi, że Content-Location nie jest zdefiniowany dla POST i PUT. Nagłówek lokalizacji jest używany z 201-Create. Zwracanie lokalizacji nie powoduje automatycznego przekierowania, potrzebujesz do tego kodu odpowiedzi 3XX.
Darrel Miller
1
Nagłówek lokalizacji jest używany (w odpowiedzi 201) do wskazania, gdzie znajduje się utworzony zasób; nie ma znaczenia dla treści odpowiedzi, której towarzyszy. Chodziło mi o to, że - jeśli chcesz uwzględnić utworzony zasób w samej odpowiedzi 201 (zamiast kierować / przekierowywać klienta do innego URI), to nagłówek lokalizacji zawartości byłby dobrym pomysłem. Jest to prawdopodobnie „naginanie reguł”, ale jest bardziej wydajne niż wymaganie kolejnego cyklu żądanie / odpowiedź w celu przekazania klientowi stanu nowego zasobu.
Mike
To ma dla mnie sens. Nigdy wcześniej nie korzystałem z nagłówka Content-Location.
Darrel Miller
jeśli klient jest człowiekiem z przeglądarką, zwrócenie 201 z nagłówkiem Location nie ma sensu. Użytkownik nie będzie wiedział, co z tym zrobić. jeśli klient jest robotem, można go zaprogramować, aby wiedział, jak sobie z nim poradzić - tak jak kontynuacja GET w lokalizacji.
niezaprzeczalny
3
@irreputable: Uważam, że REST był przeznaczony do projektowania interfejsów API, gdzie A nie oznacza agenta użytkownika, który szuka kodu HTML do renderowania.
Hermes,