REST API - wiele endpointów zmiany statusu z różnymi parametrami

REST API - wiele endpointów zmiany statusu z różnymi parametrami
PL
  • Rejestracja:prawie 7 lat
  • Ostatnio:ponad 2 lata
  • Postów:45
1

Hej wszystkim,
Probuje znalezc najlepsze rozwiazanie dla zadesignowania REST API, ale niestety wiekszosc artykulow opisuje proste interfejsy. W moim przypadku mam obecnie endpoint do zmiany statusu zamowienia

Kopiuj
PUT <url>/orders/{orderID}

zamowienie moze miec rozne statusy (zamkniete, oczekujace, zablokowane, wyslane do weryfikacji). Problem w tym ze dla kazdego z tych statusow roznia sie parametry ktore API przyjmuje (np zmiana statusu na oczekujace wymaga przekazania localdatetime z czasem oczekiwania. Natomiast zmiana status na zamkniete nie wymaga podania zadnego czasu). W wyniku tego powstala wielka metoda w kontrolerze ktora przyjmuje wszystkie mozliwe parametry dla wszystkich statusow:

                       @RequestParam Status status,
                       @RequestParam String blockerReason,
                       @RequestParam Approver approverPerson,
                       @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endTime)

Moze wyglada to spoko z poziomu API (jeden endpoint), ale bardzo mi sie nie podoba w kodzie. Metoda przyjmuje wiele parametrow z ktorych wiekszosc jest nie wykorzystana. Na poczatku trzeba zrobic ifa sprawdzajac status i potem uzyc parametry potrzebne dla tego procesu.

Chcialbym to rozbic na mniejsze metody z mniejsza iloscia parametrow z ktorych wszystkie sa potrzebne. Przykladowo, metoda zmieniajaca status na oczekujace przyjmowalaby jedynie dwa potrzebne parametry:

Kopiuj
     @PutMapping(value = "/{...}", produces = {"application/json"})
    public void changeToWating(@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endTime) {

Nie byloby tez koniecznosci sprawdzania jaki jest status tak jak aktualnie, bo byloby to API do zmieniania statusu na oczekujace, wiec wiemy ze status powinien byc ustawiony na oczekujace.
Problem jest taki ze nie wiem jak zaprojektowac API pod to. Wiekszosc dobrych praktych mowi ze nie powinno uzywac sie czasownikow, wiec API w stylu /orders/{orderId}/changestatus/waiting raczej nie wyglada dobrze.

Mieliscie moze podobne przypadki? Jak je rozwiazaliscie?

edytowany 2x, ostatnio: cerrato
somekind
zadesignowania - WAT?
ZD
  • Rejestracja:około 3 lata
  • Ostatnio:ponad rok
  • Postów:2310
1
platinium napisał(a):

. Wiekszosc dobrych praktych mowi ze nie powinno uzywac sie czasownikow, wiec API w stylu /orders/{orderId}/changestatus/waiting raczej nie wyglada dobrze.

w REST API zwany też niesłusznie Web API
Ale to tylko jeden z rodzajów. Niestety w głowach panuje monokultura, i węższą koncepcję się utożsamia z szerszą (ogólną)

W API jak najbardziej mogą być czasowniki, a nawet powinny.

Problem jest taki, że w REST literka S oznacza State. Los może przynieść dwa rozwiązania:
a) tak przemyśleć State, być może w innej klasie da się o tym mówić jako o rzeczowniku. To czasem będzie mówienie jak Kali, ale sie da bez czasowników
b) zgwałcony REST, nie twój pierwszy, nie ostatni

W mojej opinii wolne od gwałcenia jest modelowanie w jakiejś formie RPC (bo czasownik jest tam jak najbardziej OK). O historycznych i nowoczesnych RPC można długo gadać.


If you put a million monkeys at a million keyboards, one of them will eventually write a Java program - the rest of them will write Perl
edytowany 1x, ostatnio: ZrobieDobrze
RequiredNickname
  • Rejestracja:prawie 5 lat
  • Ostatnio:około 8 godzin
  • Postów:614
piotrpo
  • Rejestracja:ponad 7 lat
  • Ostatnio:minuta
  • Postów:3277
9

Widzisz jedynie proste tutoriale, bo REST jest do rozwiązywania prostych problemów. Z natury sam w sobie dotyczy jedynie prostych (CRUD) operacji, na hierarchicznie zorganizowanych zbiorach danych i praktycznie każde wyjście poza te ramy powoduje, że projektant czuje się, jak gdyby próbował naprawiać zegarek młotkiem, albo wbijać gwoździe zegarkiem go:

  • W rzeczywistych zastosowaniach mamy jakiś graf relacji, a ujęcie hierarchiczne jest tylko jedną z wielu perspektyw dla każdego grafu.
  • POST, GET, PUT, DELETE mają się mapować 1:1 na CRUD, a jak przychodzi do "zwiększ o 10% cenę wszystkich niebieskich spodni", to okazuje się, że "czegoś zabrakło".

W wyniku tego, REST jest takim schematem o którym wszyscy mówią, a właściwie nikt go nie widział w czystej formie.

W kwestii praktycznej, jeżeli stajesz przed wyborem "czytelne API", a "czytelny kod", to zawsze trzeba wybrać bramkę #1. To trochę taki problem jak z UI i zorganizujmy je inaczej, bo tak nam bardziej pasuje do "mój kod taki piękny".

ZD
A GraphQL prawidłowo użyty spełnia w Ciebie oczekiwania "wszystkie niebieskie spodnie +10% "?
piotrpo
Nie znam GraphQL na tyle dobrze, żeby odpowiedzieć na to pytanie. miałem z nim do czynienia jedynie przy jakichś tam zabawach z FB i zdecydowanie problemem jest złożoność od strony użycia API. Od strony implementacji może być jeszcze gorzej.
ZD
  • Rejestracja:około 3 lata
  • Ostatnio:ponad rok
  • Postów:2310
1

@piotrpo:

Pięknie napsiane, będę powtarzał.

Jakoś tak jest, że historii polityczno-gospodarczej przychodzi kiedyś czas, ze następuje opisanie DALCZEGO kraj X kretyńsko wyciął swoją bioróżnorodność, i pokrył 90% ziemi uprawnej kukurydzą / bananem / soją. Wiemy jakie ambicje polityków za tym stały, jakie problemy państw NIBY to miało uzdrowić, jaki szarlatan pseudonaukowiec zdobył zbyt mocną pozycję (np Miczurin), jak "przekonywano" niepokornych itd

Ale my chyba nie doczekamy się takiego opracowania, dlaczego REST zdominował i zabił inne formaty integracji.

Ludzie uniwersytetów zawsze będą proponować fajne na tablicy uproszczone modele (w sumie każdy model we wszechświecie jest uproszczeniem życia), do Roya Fieldinga nic nie mam ... nawiasem mówiąc nie spotkałem się z jakąkolwiek jego publiczną wypowiedzią, jak Ojciec ocenia to co naprawdę się z jego dzieckiem REST-em robi w realnej praktyce korporacyjnej.
Jak ktoś z was trafił na takową, pls podać linkę


If you put a million monkeys at a million keyboards, one of them will eventually write a Java program - the rest of them will write Perl
Aventus
  • Rejestracja:prawie 9 lat
  • Ostatnio:ponad 2 lata
  • Lokalizacja:UK
  • Postów:2235
5

zamowienie moze miec rozne statusy (zamkniete, oczekujace, zablokowane, wyslane do weryfikacji). Problem w tym ze dla kazdego z tych statusow roznia sie parametry ktore API przyjmuje (np zmiana statusu na oczekujace wymaga przekazania localdatetime z czasem oczekiwania. Natomiast zmiana status na zamkniete nie wymaga podania zadnego czasu). W wyniku tego powstala wielka metoda w kontrolerze ktora przyjmuje wszystkie mozliwe parametry dla wszystkich statusow:

Właśnie dla tego coraz częściej powtarzam że REST wcale nie powinno być domyślnym wyborem, a ludzie błędnie używają REST jako synonim dobrze napisanego API. Wszystko ma swoje zastosowania, oraz takie scenariusze gdzie się coś nie sprawdza.

Moim zdaniem to czego potrzebujesz to task-based API. W przypadku który opisujesz będziesz miał nowy endpoint dla odpowiedniej operacji (np. zamknięcie zamówienia), z DTO stworzonym pod ten konkretny endpoint.


Na każdy złożony problem istnieje rozwiązanie które jest proste, szybkie i błędne.
ZD
  • Rejestracja:około 3 lata
  • Ostatnio:ponad rok
  • Postów:2310
0
Aventus napisał(a):

Właśnie dla tego coraz częściej powtarzam że REST wcale nie powinno być domyślnym wyborem, a ludzie błędnie używają REST jako synonim dobrze napisanego API. Wszystko ma swoje zastosowania, oraz takie scenariusze gdzie się coś nie sprawdza.

Moim zdaniem to czego potrzebujesz to task-based API. W przypadku który opisujesz będziesz miał nowy endpoint dla odpowiedniej operacji (np. zamknięcie zamówienia), z DTO stworzonym pod ten konkretny endpoint.

Nie żebym chciał być adwokatem diabła, ale przypominają mi sie trzy literki RPC (niekoniecznie implementacje, niektóre są bardzo przeżyte, ale ta grupa sobie dzielnie choć niszowo żyje)
Taki jest Apache Thrift (wręcz postulowane DTO jest klasą/strukturą) czy gRPC
Współczesne RPC całkiem dobrze się bronią przed zmiennością / rozwojem protokołu, co apostołowie REST/JSON próbują rozgrywać jako zaletę specyficzną jedynie dla tego środowska.


If you put a million monkeys at a million keyboards, one of them will eventually write a Java program - the rest of them will write Perl
piotrpo
  • Rejestracja:ponad 7 lat
  • Ostatnio:minuta
  • Postów:3277
1

@ZrobieDobrze: Żeby nie było, ja uważam REST za fajną sprawę, jedynie nie uważam, że jego jak to wyżej określiłeś "gwałcenie" jest czymś, czego należy unikać za wszelką cenę. Oczywiście CRUD nie pasuje 1:1 do większości aplikacji, ale z drugiej strony, jest w stanie pokryć zdecydowaną większość operacji i zostaje parę, gdzie trzeba trochę naciągnąć kołderkę. Przykładem są te wyżej wymienione "czasowniki".
Ja nie mam nic przeciwko POST /goods/pants/command?color=blue, ani POST /goods/pants/multiplyPrice/1.1?color=blue jak ktoś sobie przyjmie taką spójną konwencję w swoim projekcie.

Ogromną zaletą REST, jest to, że jest to prosta, popularna konwencja. To upraszcza podłączenie się do takiego API. Gorzej, jak ktoś zaczyna marudzić, że nie możemy np. zaimplementować wyszukiwania po obrazku, bo wyszukiwanie musi być parametrem query, a zakodowana bitmapa wyskoczy poza limit.

WeiXiao
  • Rejestracja:około 9 lat
  • Ostatnio:około 23 godziny
  • Postów:5108
0

to co piszę @piotrpo

POST <url>/orders/{orderID}/change_status/1
POST <url>/orders/{orderID}/change_status/2
POST <url>/orders/{orderID}/change_status/3

wady:

hardcoded url, gdy nastąpią zmiany w statusach to trzeba będzie pamiętać o zmianach

traci się wygodę z perspektywy wołającego API

zalety:

nie wymaga dużego przemeblowania w appce,

przejrzyste API i jego input w np. swaggerze,

wysyłane są tylko potrzebne rzeczy

edit.

A gdybyś nadal miał 1 endpoint który zbiera wszystko, a w jego implementacji sobie to rozbił?

Kopiuj
switch (nextStatus)
{
	case 1: return handleNew(id, param1);
	case 2: return handleAccepted(id, param2, param3);
	case 3: return handleModified(id, param4);	
	case 4: return hadneClosed(id);
}
edytowany 8x, ostatnio: WeiXiao
RequiredNickname
Łamanie srp na poziomie api i ciężkie do zrozumienia
Black007
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 6 godzin
1

Cześć, jak masz taki case to ja bym użył polimorfizmu.
Tworzysz request Typu Order, i dla niego klasy pochodne ClosedOrder, PendingOrder itd.
Teraz używasz tej bibliotaki: https://github.com/infobip/infobip-jackson-extension

I masz sytuacje, gdzie do kontrolera przychodzi Order i w zależności od tego, jakiego jest typu tak go obsługujesz.
Możesz użyć stwich case, ale ja bym użył wzorca strategii.


"Nie popełnia błędów tylko ten, kto nic nie robi"
ZD
Trochę przemieściłeś punkt ciezkości wątku. Zaczęło się od konstrukcji drzewa REST, doszedłeś do serializacji JSON
RequiredNickname
Ojoj od osobnych dto per endpoint przeszliśmy do jakichś strategii, dziedziczenia, switchy itp. Nie idzie to imho w dobra stronę.
artur52
Powinna być opcja dawania łapek w dół, tak samo jak na SO...
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)