2015-09-09 49 views
13

Rozważmy następujące gruboziarnistej API REST dla zasobu KontaktJak obsługiwać polecenia w REST podczas wspólnego korzystania z usług REST, CQRS i EventSourcing?

POST   /api/contacts        
GET   /api/contacts        
GET   /api/contacts/:id       
PUT   /api/contacts/:id       
DELETE  /api/contacts/:id       

Rozważ użycie eventsourcing dla zasobu kontaktowej, czyli rozkazy są sprawdzane i zdarzenia są przechowywane. Zatem każde zdarzenie musi być przechowywane, w tym każda zmiana poziomu pola.

CreateContactCommand -> | Contact("john", "doe", 25) | -> ContactCreatedEvent 
FirstNameChangeCommand -> | Contact("jane", "doe", 25) | -> FirstNameChangedEvent 
LastNameChangeCommand -> | Contact("jane", "dear", 25) | -> LastNameChangedEvent 
AgeChangeCommand -> | Contact("jane", "doe", 30) | -> AgeChangedEvent 

Teraz, łącząc REST i EventSourcing oba.

Wykonywanie REST, w jaki sposób klient komunikuje się z powyższymi standardowymi interfejsami API usług REST w celu zmiany na poziomie pola, aby wygenerować polecenia po punkcie końcowym REST po stronie serwera?

Najważniejsze pytanie brzmi: jak zaprojektować interfejs REST API, aby mógł on obsługiwać polecenia, które ostatecznie wspierają eventourcing?

Jeśli ktokolwiek mógłby rzucić światło na to, pomoc byłaby bardzo ceniona.

+0

Powiązane: http://stackoverflow.com/q/30074785/126014 –

+0

Czy istnieje szczególny powód, aby krzyczeć na nas (pisanie pogrubioną czcionką)? –

Odpowiedz

9

CQRS i Sourcing zdarzeń nie jest ani zasadą projektowania interfejsu API, ani nie jest architekturą najwyższego poziomu. Jeśli jednak chcesz "udostępnić" swój interfejs API jako oparty na zadaniach interfejs API API, możesz odsłonić łącza jako część kontaktu zasób.

GET /contacts/1234 

Response

200 OK 
<contact> 
    <atom:link href="/contacts/1234/first-name" rel="first-name" /> 
    <atom:link href="/contacts/1234/last-name" rel="last-name" /> 
    <atom:link href="/contacts/1234/age" rel="age" /> 
    <first-name>Jane</first-name> 
    <last-name>Doe</last-name> 
    <age>25</age> 
</contact> 

Zakłada się tutaj, że zmienisz API do prawdalevel 3 REST API.

Również /contacts/1234 zaakceptuje tylko GET i DELETE (niePUT) wnioski. Jeśli klient chce zmienić np. pierwsza nazwa kontaktu, musi śledzić link z typem związku first-name i zrobić PUT żądania wobec tego zasobu:

PUT /contacts/1234/first-name 
<first-name>John</first-name> 

nic innego niż first-name dziedzinie PUT tutaj powinny być pominięte lub odrzucone.

Tak więc, gdy usługa otrzymuje PUT przeciwko pierwszej nazwie, jest to polecenie zmiany imienia kontaktu.

To jeszcze nie jest właściwa zadanie oparte API ponieważ nie uchwycić dlaczego pierwsze zmiany nazwy, ale mam nadzieję, że masz pomysł.

+0

Dzięki Mark za kliknięcie pomysłu. Pomoże mi zacząć. – PainPoints

+1

+1 do "To nie jest właściwy interfejs użytkownika oparty na zadaniach". Możliwe, że twoje polecenia i zdarzenia są zbyt szczegółowe, aby twój system był zdrowy psychicznie. – guillaume31

+1

Więc jeśli chcesz zmienić imię i nazwisko, musisz przygotować 2 wnioski? Musisz też osobno obsłużyć każde z tych żądań. Napisanie ogólnego programu obsługi poprowadzi cię do implementacji rodzaju metody PATCH ... Wygląda co najmniej dziwnie. – Savash

-1

REST to rozproszony aplikacyjny styl architektoniczny dla sieci. Sieć ma własne reguły i ograniczenia, jest to obszar reprezentacji i zasobów, a nie zadań, poleceń i zapytań.

Sieć jest niższa niż Twoja aplikacja. Projektując swoje zasoby HTTP, musisz pomyśleć o buforowaniu, wersjonowaniu, powtarzalności, wydajności, luźnym sprzężeniu w kontekście sieciowym, więc możesz nie chcieć, aby były dokładnie dopasowane do jednostek domen, , nie mówiąc już o właściwościach tych podmiotów.Ponadto protokół HTTP ma bardzo ograniczoną liczbę czasowników, a gdy komendy zawodzą, zasoby niekoniecznie są najlepszym wyborem do opisania zadania lub działania.

Dlatego ścisła relacja jeden-do-jednego między poleceniami, które mają sens w Twojej domenie i para (zasobów, czasowników), nie zawsze jest pożądana lub odpowiednia. Możesz chcieć pójść dalej i zaprojektować własny protokół aplikacji dla klientów REST, aby rozmawiać z serwerem zgodnie z zasadami. DAP jest odzwierciedlone w hiper-linkowych powiązaniach i relacjach dla przejść, jak zauważył Mark, ale można również użyć niestandardowych typów treści, aby lepiej opisać rodzaj ładunku w żądaniach lub odpowiedziach. Mogą na przykład zawierać typ wysyłanego polecenia domeny.

Jeśli spojrzysz na this article, zobaczysz, że para (POST, api/inventoryItem/{id}) nie jest unikalna na wykresie w "Zasobach". Może być używany do transportu RemoveItemsFromInventoryCommand lub CheckInItemsToInventoryCommand. Sposób określenia, że ​​na poziomie żądania HTTP używa się niestandardowego nagłówka typu treści: Content-Type:application/json;domain-model=RemoveItemsFromInventoryCommand lub Content-Type:application/json;domain-model=CheckInItemsToInventoryCommand.

+0

Witam guillaume31, Myślę, że również dostaję szansę wyjaśnienia. Czy przy projektowaniu DAP dobrze jest ujawniać zachowanie zasobów w taki sposób, jak w artykule, o którym wspomniałeś? lub podążać za projektem interfejsu REST API na poziomie 3, jak zaznaczył Mark? Czy powinienem wybrać sposób, który jest dla mnie łatwiejszy? – PainPoints

+0

W artykule opisano także interfejs API REST poziomu 3. Wszystko, co powiedział Mark, pozostaje aktualne. Chodzi o to, że twoje polecenia nie przechwytują zamiaru użytkownika (* UI opartego na zadaniach *) IMO. Są bardzo ziarniste, schodząc do poziomu pola. W ten sposób zmuszeni jesteście albo obstawiać każde pole jednostki w zasób, który uważam za niepraktyczny, albo znajduję inny sposób, na przykład za pomocą typów mediów. Ale oba pozostałyby na poziomie 3 w modelu dojrzałości RESTRESONON REST. – guillaume31

+0

Umieszczenie nazwy polecenia w adresie URL lub nagłówku Content-Type, jak to jest inne? Nie chodzi również o przekazanie państwa. – arnaud576875