REST: zasoby, reprezentacje i semantyka HTTP
- data
- kategoria
- Backend
- także w
- Software Architecture · System Design
- czytanie
- 1 min / 226 słów
REST często redukuje się do schematu:
GET /users
POST /users
DELETE /users/42
To użyteczna konwencja, ale nie definicja REST.
REST jest stylem architektonicznym opartym między innymi na zasobach, reprezentacjach, statelessness i jednolitym interfejsie.
Zasób nie jest rekordem JSON
Załóżmy, że istnieje użytkownik:
/users/42
Tożsamością zasobu jest URI.
JSON jest jedną z jego reprezentacji:
{
"id": 42,
"name": "Alice"
}
Ten sam zasób mógłby teoretycznie mieć inną reprezentację:
Accept: application/json
lub:
Accept: text/html
REST rozdziela więc:
resource
!=
representation
HTTP wnosi semantykę
Dobrze zaprojektowane API wykorzystuje znaczenie metod HTTP.
GET /users/42
odczytuje reprezentację.
DELETE /users/42
usuwa zasób.
PUT /users/42
zwykle oznacza zastąpienie reprezentacji.
PATCH /users/42
częściową modyfikację.
To ważniejsze niż estetyka URL-i.
HTTP ma już pojęcia takie jak:
- safe methods,
- idempotency,
- cacheability,
- conditional requests.
API może z nich korzystać zamiast budować własny protokół wewnątrz POST.
Statelessness
Każdy request powinien zawierać informacje potrzebne do jego obsłużenia.
To nie oznacza:
serwer nie przechowuje żadnego stanu.
Serwer oczywiście przechowuje stan domeny.
Chodzi o brak ukrytego kontekstu konwersacji wymaganego do zrozumienia kolejnego requestu.
request N
request N+1
Drugi request nie powinien wymagać lokalnej, tymczasowej sesji protokołu stworzonej przez pierwszy, poza jawnie modelowanym stanem aplikacji.
Gdzie REST zaczyna być niewygodny
Wyobraźmy sobie operację:
approve invoice
Możemy próbować modelować ją jako zmianę zasobu:
PATCH /invoices/42
{
"status": "approved"
}
Ale czy każda operacja domenowa naprawdę jest prostą zmianą pola?
Co z:
recalculate invoice
send invoice
archive invoice
retry payment
generate report
Da się wszystko opisać zasobami.
Pytanie brzmi, czy zawsze warto.
Jeżeli API jest silnie operacyjne, model zasobowy może zacząć ukrywać prawdziwą semantykę domeny.
Wtedy naturalną alternatywą staje się RPC:
zamiast: manipulate resource
robimy: invoke operation
To nie jest krok „wstecz”.
To inny model API.