Jak zaprojektować interfejs API REST do obsługi operacji innych niż CRUD?

11

Próbuję przekonwertować zestaw usług opartych na SOAP na interfejs API RESTful.

Zacząłem od identyfikacji zasobów, analizując nazwy operacji i dostałem zasób Subscription.

Kiedy muszę zaktualizować stan subskrypcji, nie mogę po prostu wysłać POSTżądania do serwera, ponieważ nie mam bezpośredniego dostępu do zasobów, ale muszę wywołać niektóre operacje w stylu RPC, aby zaktualizować ich właściwości. Dodatkowo tylko i tylko wtedy, gdy zmieniam stan subskrypcji na „aktywny”, wymagane jest dodatkowe połączenie z usługą zewnętrzną.

W takich przypadkach, jaka jest najlepsza praktyka obsługi podstawowych operacji?

Rozwiązaniem, które wymyśliłem, jest użycie parametrów zapytania, aby w razie potrzeby zadzwonić do usługi aktywacji, mogę użyć czegoś takiego:

POST /subscriptions/{subscriptionid}/?activate=true

Biorąc pod uwagę, że nie mogę bezpośrednio zaktualizować moich pól obiektów subskrypcji, czy istnieje jakaś najlepsza praktyka do obsługi tego rodzaju konwersji?

Aktualizacja 1:

Mogę podać w treści mojego żądania POST niektóre wartości, na przykład „stan”: „aktywny”

i sprawdź w mojej usłudze, jakie operacje mają zostać uruchomione.

Vektor88
źródło
Odwzorowanie poleceń REST na czasowniki HTTP kończy się niepowodzeniem przy złożonych operacjach. Lepiej jest po prostu zadzwonić w stylu RPC POST ActivateSubscription / {id} nikt się tym nie pomyli
Ewan
@Ewan Nie jestem pewien, czy jest to zgodne z modelem RESTful, ale wpadłem na inne rozwiązanie: w moim kodzie mogę wywołać odpowiednią operację w stylu RPC zgodnie z ładunkiem wejściowym (mogę przekazać stan = aktywny w treści mój post post, kod wywoła kod aktywacyjny)
Vektor88
1
Aktualizacja istniejącego zasobu, takiego jak ten, powinna być PATCH, a treść zapytania jest wówczas częściowym modelem tego, co zmieniasz. POST ma być żądaniem, które tworzy zasób. To rozróżnienie, oprócz tego, że jest bardziej zrozumiałe dla użytkownika, ułatwi Twojemu kodowi rozpoznanie, kiedy ma miejsce ta operacja, zamiast postu zasobów.
Pan Cochese,
1
@ Vektor88 Zazwyczaj są to jednak idempotentne operacje, w których należy przekazać całą reprezentację stanu zasobów. Ten przypadek użycia wydaje się być bardziej częściową aktualizacją, która naprawdę dobrze pasuje do PATCHA.
Pan Cochese,
1
@MrCochese POST nie jest idempotentny.
JimmyJames

Odpowiedzi:

8

Musisz obejrzeć ten wykład Jima Webbera.

Kiedy muszę zaktualizować stan subskrypcji, nie mogę po prostu wysłać żądania POST do serwera, ponieważ nie mam bezpośredniego dostępu do zasobów, ale muszę wywołać niektóre operacje w stylu RPC, aby zaktualizować ich właściwości. Dodatkowo tylko i tylko wtedy, gdy zmieniam stan subskrypcji na „aktywny”, wymagane jest dodatkowe połączenie z usługą zewnętrzną.

Pomyśl „wiadomości”; wyślij wiadomość do swojej domeny, opisując, co chcesz zrobić. Skutkiem ubocznym komunikatu jest fakt, że model domeny faktycznie zmienia swój stan. „Zasób” to kolejka komunikatów.

POST /subscriptions/{subscriptionid}/?activate=true

Pisownia nazwy zasobu nie ma znaczenia dla maszyn; ale ludzie robią się wybredni, gdy używane identyfikatory łamią konwencję, że zasoby to „rzeczowniki”.

Mówimy również o zasobie, który jest podporządkowany /subscriptions/{subscriptionid}, więc konwencja (patrz RFC 3986 ) wymaga wyrażenia tej relacji za pomocą segmentu ścieżki zamiast korzystania z części zapytania.

Więc te pisownie mogą być rozsądne

POST /subscriptions/{subscriptionid}/messages
POST /subscriptions/{subscriptionid}/activations
VoiceOfUnreason
źródło
1
Dyskusja Jima Webbera jest dostępna na youtube.com/watch?v=aQVSzMV8DWc
user674669,
0

Jeśli jest to flaga logiczna do aktywacji / dezaktywacji rzeczy, powiedziałbym, że domyślnie jest użycie JSON:

POST /subscriptions/{subscriptionid}/
{
    format: 0,
    subscription: 
    {
        active: false
    }
}

Można to łatwo rozszerzyć, jeśli chcesz obsługiwać więcej właściwości. Innym podejściem jest nadanie mu własnego punktu końcowego:

POST /subscriptions/{subscriptionid}/active/
DELETE /subscriptions/{subscriptionid}/active/

Osobiście użyłbym tego tylko wtedy, gdy activestan tego zdarzenia wymaga / ma właściwości, które można przekazać / uzyskać w JSON, takie jak identyfikator użytkownika lub ustawienie.

Jeśli nie jest to wartość logiczna, ale tylko działanie, które musisz wyzwolić, ale nie potrzebujesz / nie masz żadnych informacji zwrotnych o stanie (z wyjątkiem natychmiastowego 200 OK), użyłbym takiego punktu końcowego, aby wywołać go podobnie jak RPC:

POST /subscriptions/{subscriptionid}/activate/

W razie wątpliwości przeczytaj to: http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api#restful (patrz „Co z działaniami, które nie pasują do świata operacji CRUD? „)

Barry Staes
źródło
0

REST nie działa. Activatejest czasownikiem i nie może być stanem, Activejest stanem.

Ponieważ usługa RESTful nie działa, nie można powiedzieć usłudze RESTful, co ma robić, ale można dodać pracę do kolejki usługi.

Zobacz:

PUT /subscriptionQueue
subscriptionId={subscriptionId}
active=true

To żądanie jest RESTful i obsługuje wszystkie zalety RESTful (takie jak wydajność, kwas ...)

Peter Rader
źródło