Jak utworzyć adresy URL REST bez czasowników?

283

Próbuję ustalić, jak zaprojektować spokojne adresy URL. Jestem zwolennikiem spokojnego podejścia do używania adresów URL z rzeczownikami, a nie czasownikami, nie rozumiem, jak to zrobić.

Tworzymy usługę wdrożenia kalkulatora finansowego. Kalkulator pobiera kilka parametrów, które prześlemy za pomocą pliku CSV. Przypadki użycia obejmowałyby:

  1. Prześlij nowe parametry
  2. Uzyskaj najnowsze parametry
  3. Uzyskaj parametry dla danej daty biznesowej
  4. Uaktywnij zestaw parametrów
  5. Sprawdź poprawność zestawu parametrów

Rozumiem, że spokojnym podejściem byłoby mieć następujące adresy URL:

/parameters
/parameters/12-23-2009

Pierwsze trzy przypadki użycia można osiągnąć za pomocą:

  1. POST, w którym dołączasz plik parametrów do żądania postu
  2. POBIERZ pierwszy adres URL
  3. Uzyskaj drugi adres URL

Ale w jaki sposób robisz czwarty i piąty przypadek użycia bez czasownika? Czy nie potrzebujesz adresów URL takich jak:

/parameters/ID/activate
/parameters/ID/validate

??

Marcus Leon
źródło
3
Wolę PATCH niż POST dla częściowej aktualizacji.
user2016971,

Odpowiedzi:

71

Być może coś takiego:

PUT /parameters/activation HTTP/1.1
Content-Type: application/json; encoding=UTF-8
Content-Length: 18

{ "active": true }
yfeldblum
źródło
1
POSTjest OK, jeśli musisz wykonać „procedurę”, taką jak weryfikacja parametrów za każdym razem, gdy wysyłasz żądanie. Ale modyfikując stan (aplikacji) zasobu, faktycznie aktualizujesz istniejący zasób, nie tworzysz nowego zasobu ani nie wysyłasz żądania przetwarzania.
Andrey Vlasovskikh
19
PUT służy do tworzenia nowego zasobu lub umieszczania (w całości, a nie częściowo) nowego zasobu pod określonym adresem URL. Nie rozumiem, jak PUT pasuje do tej skrzynki.
Breton
30
Właściwie POSTvs PUTnie jest dokładnie tak, jak insertvs update. PUTaktualizuje zasób odpowiadający danej ścieżce lub tworzy nowy zasób odpowiadający danej ścieżce. POSTtworzy gdzieś nowy zasób. Na przykład PUT /blog/posts/3/comments/5zaktualizuje odpowiedni komentarz, a jednocześnie POST /blog/posts/3/commentsutworzy nowy commentzasób (i powinien zwrócić ścieżkę do nowego zasobu w odpowiedzi).
yfeldblum
23
@Justice @Breton Ważniejszą różnicą jest to, że PUTjest idempotentna, podczas gdy POSTnie jest. Zwykle powinieneś nakładać jak najwięcej ograniczeń na to, co zapewniasz w wyniku, jak to możliwe. Trzymanie się PUTdaje więcej informacji klientowi usługi.
Andrey Vlasovskikh
3
Zasobem może być również / parametry / status, a treść żądania może być po prostu „aktywna”. W ten sposób umieszczasz całkiem nowy zasób pod określonym adresem URL.
Carlos Aguayo
991

Ogólne zasady dobrego projektowania URI:

  • Nie używaj parametrów zapytania do zmiany stanu
  • Nie używaj ścieżek o różnej wielkości liter, jeśli możesz na to pomóc; małe litery są najlepsze
  • Nie używaj rozszerzeń specyficznych dla implementacji w swoich identyfikatorach URI (.php, .py, .pl itp.)
  • Nie wpadaj w RPC ze swoimi identyfikatorami URI
  • Czy ograniczyć przestrzeń URI jak najwięcej
  • Dbaj o to, aby segmenty ścieżki były krótkie
  • Do wolę albo /resourceczy /resource/; utwórz 301 przekierowań z tego, którego nie używasz
  • Czy parametry stosowanie zapytań dla sub-wybór zasobu; tj. paginacja, wyszukiwane hasła
  • Do przenieść rzeczy z URI, które powinny znajdować się w nagłówku HTTP lub organu

(Uwaga: nie powiedziałem „projekt RESTful URI”; URI są zasadniczo nieprzejrzyste w REST.)

Ogólne zasady wyboru metody HTTP:

  • Nigdy nie używaj GET do zmiany stanu; to świetny sposób, aby Googlebot zrujnował Twój dzień
  • Nie używaj PUT, chyba że aktualizujesz cały zasób
  • Nie używaj PUT, chyba że możesz również legalnie wykonać GET na tym samym URI
  • Nie używaj testu POST do pobierania informacji, które są trwałe lub które mogą być uzasadnione w buforze
  • Nie wykonuj operacji, która nie jest idempotentna z PUT
  • Czy używanie dostać za jak najwięcej
  • Czy używanie POST zamiast umieścić w razie wątpliwości
  • Czy używanie POST, gdy trzeba coś zrobić, że czuje się jak RPC
  • Czy używanie PUT dla klas zasobów, które są większe lub hierarchiczny
  • Czy użycie DELETE zamiast POST do zasobów usuni
  • Do użycie dostać za takie rzeczy jak obliczeń, chyba że wejście jest duża, w którym przypadek użycia POST

Ogólne zasady projektowania usług internetowych za pomocą HTTP:

  • Nie umieszczaj metadanych w treści odpowiedzi, która powinna znajdować się w nagłówku
  • Nie umieszczaj metadanych w osobnym zasobie, chyba że włączenie ich spowodowałoby znaczne obciążenie
  • Czy użyć odpowiedniego kodu statusu
    • 201 Createdpo utworzeniu zasobu; zasób musi istnieć w momencie wysłania odpowiedzi
    • 202 Accepted po pomyślnym wykonaniu operacji lub asynchronicznym utworzeniu zasobu
    • 400 Bad Requestgdy ktoś wykonuje operację na danych, która jest wyraźnie nieprawdziwa; dla twojej aplikacji może to być błąd sprawdzania poprawności; zazwyczaj rezerwują 500 na niewyłapane wyjątki
    • 401 Unauthorizedgdy ktoś uzyskuje dostęp do interfejsu API albo nie dostarcza niezbędnego Authorizationnagłówka, albo gdy poświadczenia w nim Authorizationsą nieprawidłowe; nie używaj tego kodu odpowiedzi, jeśli nie oczekujesz poświadczeń za pomocą Authorizationnagłówka.
    • 403 Forbidden gdy ktoś uzyskuje dostęp do Twojego interfejsu API w sposób, który może być złośliwy lub jeśli nie ma autoryzacji
    • 405 Method Not Allowed kiedy ktoś używa POST, kiedy powinien był użyć PUT itp
    • 413 Request Entity Too Large gdy ktoś próbuje wysłać ci niedopuszczalnie duży plik
    • 418 I'm a teapot podczas próby parzenia kawy za pomocą czajnika
  • Czy nagłówki buforowania użytku, kiedy tylko możesz
    • ETag nagłówki są dobre, gdy można łatwo zredukować zasób do wartości skrótu
    • Last-Modified powinien zasygnalizować, że sprawdzanie czasu aktualizacji zasobów jest dobrym pomysłem
    • Cache-Controli Expirespowinny mieć sensowne wartości
  • Rób wszystko, co możesz, aby uhonorować buforowanie nagłówków w żądaniu ( If-None-Modified, If-Modified-Since)
  • Czy stosować przekierowania gdy mają one sens, ale te powinny być rzadkie dla usługi internetowej

W odniesieniu do twojego konkretnego pytania, należy użyć POST dla # 4 i # 5. Operacje te podlegają powyższej wytycznej „podobnej do RPC”. W przypadku nr 5 pamiętaj, że POST nie musi koniecznie używać Content-Type: application/x-www-form-urlencoded. Może to być równie łatwo ładunek JSON lub CSV.

Bob Aman
źródło
11
413 jest przeznaczony do wielkości wysyłanego żądania, abyś mógł grzecznie odrzucić osobę wysyłającą ci gigantyczne dane, często w połączeniu z 411, abyś zmusił ludzi do powiedzenia, ile jest wysyłanych. W przypadku przykładu podanego przeciwko 413 uważam, że 400 byłoby bardziej odpowiednią odpowiedzią.
Garry Shutler
5
+1, ponieważ jest to świetny zasób. Jest to jednak ogólny zasób i nie odpowiada bezpośrednio na pytanie. Idealnie powinien zawierać dodatkowy akapit z konkretną odpowiedzią.
Samuel Neff,
@GarryShutler Dobry połów, masz absolutną rację. Dzięki za edycję.
Bob Aman
1
Tak, używałbyś PUT tylko w przypadkach, gdy nadpisujesz cały obiekt. Twierdzę jednak, że PATCH lub POST są uzasadnione w przypadku częściowej aktualizacji zasobu. PATCH jest bardziej klarowny, jeśli chodzi o to, co zrobi operacja, ale ponieważ nie wszyscy klienci są w stanie nawet wysłać żądanie PATCH , całkowicie zamiast tego należy zezwolić na POST , a nawet posunąć się do tego, by zalecać POST powinno być zawsze dozwolone jako awaryjne, jeśli używana jest PATCH .
Bob Aman
1
+1 za 409 błędów. Błąd 400 to problem, który można rozwiązać przez wystarczającą weryfikację po stronie klienta. 409 wyjaśnia, że ​​samo żądanie było akceptowalne i spójne, ale koliduje z pewnym aspektem stanu serwera (zwykle kontroluje współbieżność, ale teoretycznie wszelkie ograniczenia niewprowadzane na wejściu).
claytond
18

Ilekroć wygląda na to, że potrzebujesz nowego czasownika, pomyśl o zamianie go w rzeczownik. Na przykład zmień „aktywuj” na „aktywacja”, a „sprawdź” na „weryfikacja”.

Ale na podstawie tego, co napisałeś, powiedziałbym, że Twoja aplikacja ma znacznie większe problemy.

Za każdym razem, gdy proponowany jest zasób zwany „parametrem”, powinien wysyłać czerwone flagi w umyśle każdego członka zespołu projektowego. „parametr” może dosłownie dotyczyć dowolnego zasobu; to nie jest wystarczająco szczegółowe.

Co dokładnie oznacza „parametr”? Prawdopodobnie wiele różnych rzeczy, z których każda powinna mieć osobny zasób dedykowany.

Kolejny sposób na osiągnięcie tego - kiedy omawiasz swoją aplikację z użytkownikami końcowymi (tymi, którzy prawdopodobnie niewiele wiedzą o programowaniu), jakich słów używają wielokrotnie?

To są słowa, które powinieneś projektować.

Jeśli nie masz jeszcze tej konwersji z potencjalnymi użytkownikami - zatrzymaj wszystko teraz i nie pisz kolejnej linii kodu, dopóki tego nie zrobisz! Tylko wtedy twój zespół będzie wiedział, co należy zbudować.

Nie wiem nic o oprogramowaniu finansowym, ale gdybym musiał zgadywać, powiedziałbym, że niektóre zasoby mogą mieć nazwy takie jak „Raport”, „Płatność”, „Przelew” i „Waluta”.

Jest wiele dobrych książek na temat tej części procesu projektowania oprogramowania. Dwa, które mogę polecić, to wzorce projektowania i analizy oparte na domenie .

Rich Apodaca
źródło
1
To naprawdę dobry punkt. Łatwo przeoczyć, jeśli jesteś w stanie przetworzyć formalną logikę i rozumowanie. Nie ma znaczenia, czym jest X, o ile pasuje do innych części w prawidłowy sposób. Czynniki ludzkie po prostu znikają.
Breton
1
Czasami przydaje się konwersja słów na „zasób przetwarzający”, taki jak „aktywator” lub „walidator”. Zgodnie z RFC 2616 POST można wykorzystać do „Zapewnienia bloku danych ... do procesu przetwarzania danych”
Darrel Miller,
Zrozumiany. W takim przypadku użytkownicy określają dane jako „parametry” (lub „parametry ryzyka” lub coś podobnego). Lista parametrów zawiera wiele różnych typów ustawień, ale parametry są zawsze przesyłane jako cały zestaw (w pliku CSV).
Marcus Leon
@Marcus - to brzmi jak bardzo nietypowy przypadek. Być może, jeśli wyjaśnisz bardziej szczegółowo, czym zajmuje się Twoja aplikacja, będziemy w stanie zaoferować lepsze sugestie dotyczące identyfikowania zasobów.
Rich Apodaca
1
„kiedy omawiasz swoją aplikację z użytkownikami końcowymi, jakich słów oni sami używają wielokrotnie?” ... a co jeśli wszystkie są czasownikami? XD
Amalgovinus
11

Projekt twoich adresów URL nie ma nic wspólnego z tym, czy twoja aplikacja jest RESTful czy nie. Wyrażenie „RESTful URL” jest więc nonsensowne.

Myślę, że powinieneś przeczytać coś więcej na temat tego, czym tak naprawdę jest REST. REST traktuje adresy URL jako nieprzejrzyste i jako takie nie wie, co się w nich znajduje, bez względu na to, czy istnieją czasowniki, rzeczowniki czy cokolwiek innego. Nadal możesz chcieć zaprojektować swoje adresy URL, ale to dotyczy interfejsu użytkownika, a nie REST.

To powiedziawszy, przejdźmy do twojego pytania: dwa ostatnie przypadki nie są ODPOCZYNEKAMI i nie pasują do żadnego rodzaju schematu odpoczynku. Oto, co możesz nazwać RPC. Jeśli poważnie myślisz o REST, musisz od nowa przemyśleć sposób działania aplikacji. Albo to, albo zrezygnuj z REST i po prostu zrób swoją aplikację jako aplikację RPC.

Hmmm może nie.

Chodzi o to, że musisz traktować wszystko jako zasób, więc gdy zestaw parametrów ma adres URL, z którego można się do niego odwoływać, dodajesz:

GET [parametersurl]/validationresults

POST [paramatersurl]
body: {command:"activate"}

Ale znowu, rzeczą aktywującą jest RPC, a nie REST.

Bretoński
źródło
Podajesz tutaj interesujący punkt. Czy możesz rozwinąć nieco dalej, jak byłoby RESTful podejście do czegoś takiego?
poezn
Spędziłem trochę czasu, czytając odpowiedzi tutaj i myślę, że sprawiedliwość może mieć coś wspólnego. modeluje indywidualne właściwości obiektu parametrów jako indywidualne zasoby i używa czasownika PUT w celu zastąpienia zawartości tej właściwości w tym zasobie. Jest to modelowanie stanu każdego obiektu jako zbioru zasobów i modyfikowanie stanu jako umieszczanie, usuwanie lub modyfikowanie zasobu. Co do walidacji - potrzebujesz zasobu, który magicznie stwierdza, czy parametry są prawidłowe, czy nie, jak wyżej w mojej odpowiedzi. To by było w porządku, o ile nie ma żadnych skutków ubocznych.
Breton
Oczywiście pod warunkiem, że czynność „Aktywuj” ustawia tylko jedną właściwość na „prawda”. Jeśli ma zrobić coś innego, to nadal nie jest RESTful i nie jestem pewien, jak byś go modelował RESTful.
Breton
Nie sądzę, żebyś mógł powiedzieć, że ostatnie dwa przypadki nie są ODPOCZNE. W efekcie Aktywacja i Walidacja to tylko pośrednie sposoby stwierdzenia, że ​​zasób zmienia się w nowy stan w maszynie stanów. REST jest w stanie to modelować.
Darrel Miller
@Darrel, myślę, że wskazałeś część REST, która może stanowić wyzwanie dla wielu osób, które są nowicjuszami w REST. Jak możesz zacząć wdrażanie operacji „Sprawdź poprawność zasobu x”? Myślę, że wyzwaniem jest to, że jest to operacja, która może spowodować zmianę stanu, ale nowy stan jest wynikiem wysłanego żądania.
Sean
6

Wymagania dotyczące aktywacji i sprawdzania poprawności to sytuacje, w których próbujesz zmienić stan zasobu. Nie inaczej jest składanie zamówienia „zrealizowane” lub inne „złożone” żądanie. Istnieje wiele sposobów modelowania tego rodzaju zmian stanu, ale moim zdaniem, który często działa, jest tworzenie zasobów kolekcji dla zasobów tego samego stanu, a następnie przenoszenie zasobów między kolekcjami w celu wpłynięcia na stan.

np. Utwórz niektóre zasoby, takie jak

/ActiveParameters
/ValidatedParameters

Jeśli chcesz, aby zestaw parametrów był aktywny, dodaj go do kolekcji ActiveParameters. Możesz przekazać zestaw parametrów jako treść encji lub przekazać URL jako parametr zapytania w następujący sposób:

POST /ActiveParameters?parameter=/Parameters/{Id}

To samo można zrobić z / ValidatedParameters. Jeśli parametry nie są prawidłowe, serwer może zwrócić „niepoprawne żądanie” do żądania dodania parametrów do kolekcji zweryfikowanych parametrów.

Darrel Miller
źródło
1

Proponuję następujące zasoby i metody Meta.

Uaktywnij parametry i / lub sprawdź je:

> PUT /parameters/<id>/meta HTTP/1.1
> Host: example.com
> Content-Type: application/json
> Connection: close
>
> {'active': true, 'require-valid': true}
>
< HTTP/1.1 200 OK
< Connection: close
<

Sprawdź, czy parametry są aktywne i prawidłowe:

> GET /parameters/<id>/meta HTTP/1.1
> Host: example.com
> Connection: close
>
< HTTP/1.1 200 OK
< Content-Type: application/json
< Connection: close
<
< {
<     'active': true,
<     'require-valid': true,
<     'valid': {'status': false, 'reason': '...'}
< }
<
Andrey Vlasovskikh
źródło
O ile rozumiem, pytanie dotyczy nazwy spokojnych adresów URL, a nie funkcjonalności, prawda?
poezn
2
Pytanie ograniczone do „RESTful URL” jest złym pytaniem i nie należy na nie odpowiadać. Zamiast tego należy rozszerzyć pytanie, aby uwzględnić „zasoby RESTful, z powiązanymi metodami i adresami URL” - i odpowiedzieć jako takie.
yfeldblum
Jak rozumiem, pytanie dotyczyło konwencji nazewnictwa adresów URL i metod HTTP, na które powinien odpowiadać nazwany zasób.
Andrey Vlasovskikh
1

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/htmlformatu 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-urlencodedformatu reprezentacji, który jest wysyłany do wspomnianej docelowej lokalizacji za pomocą określonej metody żądania HTTP, POSTw tym przypadku. Jeśli wchodzimy 1w firstNumberpolu wprowadzania i 2do secondNumberpola wprowadzania, przeglądarka wygeneruje reprezentację firstNumber=1&secondNumber=2i 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 preloadlinkami, 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-urlencodedreprezentacji 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/csvzgodnie 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/csvbezpoś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 PUTlub 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/csva 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.

Roman Vottner
źródło
0

Edycja: Rzeczywiście, identyfikator URI uniemożliwiłby GETżądanie pozostanie idempotentem.


Jednak w przypadku sprawdzania poprawności użycie kodów stanu HTTP do powiadomienia o ważności żądania (w celu utworzenia nowego lub zmodyfikowania istniejącego „parametru”) pasowałoby do modelu Restful.

Zgłoś z 400 Bad Requestkodem stanu, jeśli przesłane dane są / są nieprawidłowe i żądanie musi zostać zmienione przed ponownym przesłaniem ( kody stanu HTTP / 1.1 ).

Polega to jednak na sprawdzeniu poprawności podczas przesyłania, a nie na odroczeniu jej, tak jak w przypadku użycia. Inne odpowiedzi mają odpowiednie rozwiązania tego scenariusza.

Derek Mortimer
źródło
Identyfikator URI ma być identyfikatorem. Użycie określonego adresu URL nie powinno mieć skutków ubocznych. Wyobraź sobie, co zrobiłby z tym serwer proxy.
Breton
2
lub google, jeśli o to chodzi. Kiedyś czytałem historię o sklepie internetowym, w którym wszystkie produkty zostały usunięte przez google z powodu tego rodzaju idiotyzmu.
Breton
0

W środowisku REST każdy adres URL jest unikalnym zasobem. Jakie są twoje zasoby Kalkulator finansowy naprawdę nie ma żadnych oczywistych zasobów. Musisz zagłębić się w parametry, które nazywasz, i wyciągnąć zasoby. Na przykład kalendarz amortyzacji pożyczki może być zasobem. Adres URL kalendarza może obejmować datę początkową, termin (w miesiącach lub latach), okres (po złożeniu odsetek), stopę procentową i zasadę początkową. Przy wszystkich tych wartościach masz określony kalendarz płatności:

http://example.com/amort_cal/2009-10-20/30yrsfixed/monthly/5.00/200000

Teraz nie wiem, co obliczasz, ale twoja koncepcja listy parametrów nie brzmi RESTful. Jak ktoś inny powiedział, powyższe wymagania brzmią bardziej XMLRPC. Jeśli próbujesz uzyskać REST, potrzebujesz rzeczowników. Obliczenia nie są rzeczownikami, są czasownikami działającymi na rzeczowniki. Musisz go odwrócić, aby wyciągnąć rzeczowniki z cieląt.

jmucchiello
źródło
5
Myślę, że głupio jest tutaj używać ukośników, co byłoby nie tak z amort_cal? Date = 2009-10-20 i type = 30yrsfixed & period = miesięcznie i stopa = 5.0 i kwota początkowa = 200000? REST nie ma znaczenia, o ile jest zasobem. URI Spec robi opieki chociaż. Jak wyobrażasz sobie względne linki do pracy z takim schematem?
Breton
Podnosisz jednak dobry punkt. Czy te „parametry” muszą nawet być przechowywane na serwerze? Jeśli jest to jednorazowe obliczenie, dlaczego nie stworzyć wirtualnej przestrzeni, w której parametry znajdują się w adresie URL. Dopóki nie zmieniasz stanu wewnętrznego, powinno być dobrze.
Breton,
1
A „parametry” nie dotyczą „zasobu”. Zasób to pojedyncza jednostka o unikalnym identyfikatorze. Mój adres URL wskazuje pojedynczy zasób. Sparametryzowany adres URL wskazuje zbiór zasobów, które wybierzesz spośród parametrów.
jmucchiello,
2
REST nie jest oparty na „zasobach CRUDing”. Umieszczenie wszystkich parametrów zapytania w segmentach ścieżki nie powoduje automatycznie powstania interfejsu RESTful, ponieważ teraz myślisz, że możesz nazwać każdą permutację zasobem. Niestety nie ma magicznego procesu, który można zastosować, aby określić, jakie powinny być zasoby w systemie. Wymaga starannego zaprojektowania, a nie mechanicznej formuły.
Darrel Miller
2
Po raz kolejny architektura REST nie DBA o to, co znajduje się w adresie URL. adres URL ma być nieprzejrzysty . Nie ma znaczenia, czy odpoczywasz, czy jako separatory używasz ukośników, średników, czy serc Unicode. Przeczytaj to i odpowiedz na to - nie na to, co według mnie mówisz.
Breton