Jest mi trochę przykro, widząc, że po ponad 10 latach nie ma tak naprawdę odpowiedzi, która mówi, w jaki sposób można zażądać OP w architekturze REST, dlatego teraz muszę to zrobić.
Po pierwsze, czym jest REST ?! Skrót REST lub ReST oznacza „Reprezentatywny transfer stanu” i określa wymianę stanu zasobu w określonym formacie reprezentacji. Format reprezentacji jest zgodny z typem wynegocjowanego nośnika. W przypadku application/html
formatu reprezentacji może to być strumień treści tekstowej w formacie HTML, który jest renderowany w przeglądarce, prawdopodobnie po zastosowaniu formatowania arkusza stylów w celu umiejscowienia niektórych elementów w określonych lokalizacjach.
REST jest w zasadzie uogólnieniem przeglądalnej sieci, którą wszyscy znamy, choć atakuje ona wszystkie rodzaje aplikacji, a nie tylko przeglądarki. Dlatego z założenia te same pojęcia, które dotyczą sieci, dotyczą również architektury REST. Pytanie, jak osiągnąć coś w sposób „RESTful”, rozwiązuje problem odpowiadania na pytanie, jak osiągnąć coś na stronie internetowej, a następnie zastosować te same koncepcje do warstwy aplikacji.
Internetowy kalkulator zwykle zaczyna się od „strony”, która pozwala wprowadzić pewne wartości do obliczenia przed wysłaniem wprowadzonych danych na serwer. W HTML jest to zwykle osiągane za pomocą <form>
elementów HTML , które uczą klienta o dostępnych parametrach do ustawienia, docelowej lokalizacji do wysłania żądania, a także formacie reprezentacji, który należy zastosować przy wysyłaniu danych wejściowych. Może to wyglądać tak:
<html>
<head>
...
</head>
<body>
<form action="/../someResource" method="post" enctype="application/x-www-form-urlencoded">
<label for="firstNumber">First number:</label>
<input type="number" id="firstNumber" name="firstNumber"/>
<label for="secondNumber">Second number:</label>
<input type="number" id="secondNumber" name="secondNumber"/>
<input type="submit" value="Add numbers"/>
</form>
</body>
</html>
Powyższy przykład, tj. Stwierdza, że istnieją dwa pola wejściowe, które może wypełnić użytkownik lub niektóre inne automaty oraz że po wywołaniu elementu wejściowego prześlij przeglądarkę formatuje dane wejściowe do application/x-www-form-urlencoded
formatu reprezentacji, który jest wysyłany do wspomnianej docelowej lokalizacji za pomocą określonej metody żądania HTTP, POST
w tym przypadku. Jeśli wchodzimy 1
w firstNumber
polu wprowadzania i 2
do secondNumber
pola wprowadzania, przeglądarka wygeneruje reprezentację firstNumber=1&secondNumber=2
i wysłać go jako ładunek ciała rzeczywistego żądanie zasobu docelowego.
Surowe żądanie HTTP wysłane do serwera może więc wyglądać następująco:
POST /../someResource
Host: www.acme.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 28
Accept: application/html
firstNumber=1&secondNumber=2
Serwer może wykonać obliczenia i odpowiedzieć kolejną stroną HTML, która zawiera wynik obliczeń, ponieważ żądanie wskazało, że klient rozumie ten format.
Jak już zauważył Breton, nie ma czegoś takiego jak „RESTful” URL lub URI. Identyfikator URI / URL jest swoistą rzeczą i nie powinien przekazywać żadnego znaczenia klientowi / użytkownikowi. W powyższym przykładzie kalkulatora użytkownik po prostu nie jest zainteresowany, gdzie wysłać dane, interesuje go tylko to, że po uruchomieniu pola wejściowego przesłania żądanie jest wysyłane. Serwer powinien podać wszystkie wymagane informacje potrzebne do wykonania zadania.
Przeglądarka może również nie zdawać sobie sprawy z tego, że żądanie faktycznie zasila kalkulator z niektórymi parametrami wejściowymi, może to być również rodzaj formularza zamówienia, który zwraca tylko kolejną reprezentację formularza w celu kontynuowania procesu zamawiania lub zupełnie innego rodzaju ratunek. Po prostu wykonuje to, czego wymaga specyfikacja HTML w takim przypadku i nie obchodzi go, co tak naprawdę robi serwer. Ta koncepcja umożliwia przeglądarce korzystanie z tego samego formatu reprezentacji do robienia wszelkiego rodzaju rzeczy, takich jak zamawianie niektórych rzeczy w preferowanym sklepie internetowym, rozmowy z najlepszymi przyjaciółmi, logowanie się do konta online i tak dalej.
Affordance niektórych elementów, np w przypadku przedstawienia wejściowe pole, które jest zwykle renderowany jako przycisk definiuje co należy się z nim. W przypadku przycisku lub łącza w zasadzie każe ci je kliknąć. Inne elementy mogą przenosić różne afordancje. Tę afordancję można również wyrazić za pomocą relacji między preload
linkami, np. Za pomocą linków z adnotacjami, które w zasadzie mówią klientowi, że może on już załadować zawartość połączonego zasobu w tle, ponieważ użytkownik najprawdopodobniej następnie przejmie tę zawartość. Takie relacje linków powinny być oczywiście znormalizowane lub zgodne z mechanizmem rozszerzenia dla typów relacji określonych przez linkowanie w sieci .
Są to podstawowe koncepcje stosowane w sieci, które powinny być również stosowane w architekturze REST. Według „wujka Boba” Roberta C. Martina architektura dotyczy zamiarów, a intencją architektury REST jest oddzielenie klientów od serwerów, aby umożliwić serwerom swobodną ewolucję w przyszłości bez obawy, że złamią klientów. To niestety wymaga dużej dyscypliny, ponieważ tak łatwo jest wprowadzić sprzęganie lub dodać rozwiązania szybkiej naprawy, aby wykonać zadanie i przejść dalej. Jak zauważył Jim Webber w architekturze REST, jako dostawca usług powinieneś spróbować zaprojektować protokół aplikacji domeny podobny do tekstowej gry komputerowej z lat 70., którą klienci będą realizować aż do końca procesu.
Niestety tak naprawdę wiele tzw. Interfejsów API „REST” w rzeczywistości to wszystko. Widoczna jest wymiana danych opartych głównie na JSON, które są określone w dokumentacji zewnętrznej specyficznej dla API, którą zwykle trudno dynamicznie zintegrować w locie. Format, w jaki musi wyglądać żądanie, jest również zapisany na stałe w dokumentacji zewnętrznej, co prowadzi do dużej liczby interpretacji identyfikatorów URI w celu zwrócenia predefiniowanych typówzamiast używać jakiegoś wspólnego formatu reprezentacji, który jest negocjowany z góry. Zapobiega to zmianie serwerów, ponieważ klienci oczekują teraz otrzymania określonego formatu danych (należy pamiętać, że nie jest to format reprezentacji!) Dla wstępnie zdefiniowanych identyfikatorów URI. Ta niestandardowa wymiana formatu danych dodatkowo uniemożliwia klientom interakcję z innymi interfejsami API, ponieważ „format danych” jest zwykle przypływem do określonego interfejsu API. Znamy tę koncepcję z przeszłości z technologii RPC, takich jak Corba, RMI lub SOAP, które potępiamy jako w jakiś sposób złe, mimo że Peppol przeszedł na nią ponownie, zastępując AS2 domyślnym protokołem przesyłania ostatnio.
Jeśli chodzi o zadane pytanie, wysyłanie danych w postaci pliku csv nie różni się niczym od używania application/x-www-form-urlencoded
reprezentacji lub podobnych rzeczy. Jim Webber wyjaśnił, że w końcu HTTP jest tylko protokołem transportowym, którego domeną aplikacji jest przesyłanie dokumentów przez Internet . Klient i serwer powinny co najmniej obsługiwać text/csv
zgodnie z definicją w RFC 7111 . Ten plik CSV może zostać wygenerowany w wyniku przetworzenia typu nośnika, który definiuje elementy formularza, element docelowy lub atrybut, do którego należy wysłać żądanie, a także metodę HTTP w celu przesłania konfiguracji.
Istnieje kilka rodzajów nośników obsługujących formularze, takie jak HTML , formularze HAL , halform , ion lub Hydra . Obecnie jednak nie znam typu nośnika, który może automatycznie kodować dane wejściowe text/csv
bezpośrednio, dlatego może być konieczne zdefiniowanie i zarejestrowanie w rejestrze typów nośników IANA .
Przesyłanie i pobieranie pełnego zestawu parametrów nie powinno być problemem. Jak wspomniano wcześniej, docelowy identyfikator URI nie ma znaczenia, ponieważ klient użyje identyfikatora URI do pobrania nowej treści do przetworzenia. Filtrowanie według daty biznesowej również nie powinno być trudne. Tutaj serwer powinien jednak mieć wszystkie możliwości, z których klient może po prostu wybrać. W ostatnich latach opracowano GraphQL i RestQL, które wprowadzają język podobny do SQL, który może być ukierunkowany na określony punkt końcowy w celu uzyskania odfiltrowanej odpowiedzi. Jednak w prawdziwym sensie REST narusza to ideę REST jako a) GraphQL, tj. Używa tylko jednego punktu końcowego, który w jakiś sposób uniemożliwia optymalne użycie buforowania ib) wymaga znajomości dostępnych pól w górę, co może prowadzić do wprowadzenia łączenia klientów do podstawowego modelu danych zasobu.
Aktywacja lub dezaktywacja niektórych parametrów konfiguracyjnych jest po prostu kwestią uruchomienia kontroli hipermedialnych, które zapewniają taką afordancję. W formularzach HTML może to być proste pole wyboru lub zaznaczenie wielu wierszy na liście lub tego rodzaju. W zależności od formy i metody, którą definiuje, może potencjalnie wysłać całą konfigurację za pośrednictwem PUT
lub być sprytnym w kwestii dokonanych zmian i wykonać tylko częściową aktualizację za pośrednictwem PATCH
. Ten ostatni wymaga w zasadzie obliczenia reprezentacji zmiany na zaktualizowaną i podaje serwerowi wymagane kroki, aby przekształcić bieżącą reprezentację w pożądaną. Zgodnie ze specyfikacją PATH należy to zrobić w ramach transakcji, aby zastosować wszystkie lub żaden z kroków.
HTTP pozwala i zachęca serwer do zweryfikowania otrzymanego żądania z góry przed zastosowaniem zmian. Dla PUT specyfikacja określa:
Serwer źródłowy POWINIEN zweryfikować, czy reprezentacja PUT jest zgodna z wszelkimi ograniczeniami serwera dla zasobu docelowego, których PUT nie może lub nie może zmienić. Jest to szczególnie ważne, gdy serwer źródłowy używa wewnętrznych informacji konfiguracyjnych związanych z URI w celu ustawienia wartości metadanych reprezentacji w odpowiedziach GET. Gdy reprezentacja PUT jest niezgodna z zasobem docelowym, serwer źródłowy POWINIEN albo uczynić je spójnym, przekształcając reprezentację lub zmieniając konfigurację zasobu, albo odpowiedzieć odpowiednim komunikatem o błędzie zawierającym wystarczające informacje, aby wyjaśnić, dlaczego reprezentacja jest nieodpowiednia. Sugerowane są kody stanu 409 (konflikt) lub 415 (nieobsługiwany typ nośnika),
Na przykład jeśli zasób docelowy jest skonfigurowany tak, aby zawsze miał typ zawartości „text / html”, a reprezentacja będąca PUT ma typ treści „image / jpeg”, serwer źródłowy powinien wykonać jedną z następujących czynności:
za. ponownie skonfiguruj zasób docelowy, aby odzwierciedlić nowy typ nośnika;
b. przekształcić reprezentację PUT do formatu zgodnego z formatem zasobu przed zapisaniem go jako nowy stan zasobu; lub,
do. odrzuć żądanie z odpowiedzią 415 (Nieobsługiwany typ nośnika) wskazującą, że zasób docelowy jest ograniczony do „text / html”, być może zawierający łącze do innego zasobu, który byłby odpowiednim celem dla nowej reprezentacji.
HTTP nie definiuje dokładnie, w jaki sposób metoda PUT wpływa na stan serwera źródłowego, poza tym, co można wyrazić intencją żądania klienta użytkownika i semantyką odpowiedzi serwera źródłowego. ...
Podsumowując ten post, powinieneś albo użyć istniejącego typu nośnika, który pozwala nauczyć klienta o wymaganych lub obsługiwanych parametrach wejściowych, docelowej lokalizacji, do której należy wysłać żądanie, operacji, a także typu mediów prośba musi zostać sformatowana lub zdefiniować własną, którą zarejestrujesz w IANA. To ostatnie może być konieczne, jeśli chcesz przekonwertować dane wejściowetext/csv
a następnie prześlij reprezentację CSV na serwer. Sprawdzanie poprawności powinno nastąpić przed zastosowaniem zmian do zasobu. Rzeczywisty identyfikator URI nie powinien mieć znaczenia dla klientów poza ustaleniem, gdzie wysłać zapytanie i jako taki może być swobodnie wybrany przez Ciebie, realizatora usługi. Postępując zgodnie z tymi krokami, zyskujesz swobodę zmiany strony serwera w dowolnym momencie, a klienci nie ulegną awarii, jeśli obsługują używane typy mediów.