Tylko POST? Zakończmy ten absurdalny spór o projektowanie API
Obalenie mitu "tylko POST" dotyczącego API, wyjaśnienie, dlaczego wynika on z niezrozumienia zasad projektowania API, oraz wyjaśnienie odpowiednich przypadków użycia stylów architektonicznych RESTful i RPC.
Niedawno zwróciła moją uwagę dyskusja na temat tego, czy projektowanie API powinno odbywać się wyłącznie za pomocą "POST". Po zagłębieniu się w ten spór stwierdziłem, że nie tylko kwestia, o którą się kłócą, jest bezsensowna, ale także ujawnia niezrozumienie istoty projektowania API przez wielu programistów. Dziś przyjrzymy się dokładniej kluczowym ideologiom projektowania API i zobaczymy, dlaczego ten spór nie powinien w ogóle istnieć.
Nieporozumienie dotyczące "tylko POST"
Ci programiści, którzy opowiadają się za używaniem "tylko POST" do zastąpienia specyfikacji API RESTful, wyraźnie nie zrozumieli najważniejszego punktu projektowania API. Ich argumenty zazwyczaj obejmują:
- Uproszczenie projektowania: Jedna metoda może obsłużyć wszystko
- Bezpieczeństwo: Parametry POST nie pojawiają się w URL
- Elastyczność: POST może przesyłać dowolną strukturę danych
Na pierwszy rzut oka te argumenty wydają się sensowne. Jednak w rzeczywistości ta perspektywa myli wybór metod HTTP ze stylami projektowania API, co są dwoma różnymi poziomami zagadnień. POST to tylko jedna z metod protokołu HTTP, podczas gdy REST to styl projektowania API.
Istota projektowania API
Zanim zaczniemy omawiać konkretne style API, musimy zrozumieć, jaki jest główny cel projektowania API. Dobre API powinno być:
- Jasne i zrozumiałe: Inni programiści (w tym Ty w przyszłości) powinni intuicyjnie rozumieć, do czego służy każde punkt końcowy (endpoint)
- Spójne: Stosowanie się do określonych specyfikacji, aby zmniejszyć koszty nauki
- Rozwijane: Możliwe do łatwego przeprowadzenia kontroli wersji i rozbudowy funkcji
- Wydajne: Uwzględniać efektywność pod względem wydajności i wykorzystania zasobów
RESTful API: Więcej niż wybór metod HTTP
RESTful API to tylko jeden z wielu stylów projektowania API, koncentrujący się na zasobach i operacjach na nich. Przykładowo, spójrzmy na prosty system blogowy, aby zobaczyć, jak można zaprojektować API RESTful:
-
Pobierz wszystkie artykuły:
-
Pobierz konkretny artykuł:
-
Utwórz nowy artykuł:
-
Zaktualizuj artykuł:
-
Usuń artykuł:
W tym przykładzie widać:
- API jest zaprojektowane wokół zasobu "artykuł"
- Różne metody HTTP są używane do reprezentowania różnych operacji
- Struktura URL jest jasna, wskazując zasób, na którym wykonywana jest operacja
To podejście do projektowania sprawia, że API jest bardziej intuicyjne i samoopisujące, co ułatwia programistom zrozumienie funkcji każdego punktu końcowego.
RPC: Zrozumienie stylu API stojącego za "tylko POST"
Celem projektowania API w stylu RPC (Remote Procedure Call) jest spowodowanie, by zdalne wywołania usług wyglądały tak prosto, jak wywoływanie lokalnych funkcji.
Co ciekawe, ci, którzy opowiadają się za "tylko POST", mogą nie zdawać sobie sprawy, że w rzeczywistości opisują styl RPC.
W porównaniu do API RESTful, RPC bardziej koncentruje się na samej operacji niż na zasobie. Dlatego typowe API w stylu RPC mają formę "czasownik + rzeczownik", na przykład getProduct(productId)
lub createUser(userData)
.
W wielu implementacjach RPC wszystkie operacje są zazwyczaj wysyłane za pomocą żądań POST do tego samego punktu końcowego, ze szczególną operacją i parametrami określonymi w treści żądania. Dlatego właśnie pomysł "tylko POST" jest w rzeczywistości bliższy RPC niż REST.
Na przykład, żądanie "pobierz produkt" w stylu RPC oparte na HTTP może wyglądać tak:
Nowoczesne ramy RPC, takie jak gRPC, oferują bardziej potężne i wydajne implementacje. Użyjmy tego jako przykładu, aby zilustrować styl RPC:
Najpierw definiujemy usługę i format wiadomości (używając Protocol Buffers):
Następnie, użycie tej usługi w kliencie Node.js jest tak proste, jak wywołanie lokalnej funkcji:
W tym przykładzie w stylu RPC można zobaczyć:
- Definicja usługi wyraźnie wymienia wszystkie dostępne operacje (w tym uproszczonym przykładzie są to
GetArticle
iCreateArticle
). - Każda operacja ma wyraźnie określone typy żądań i odpowiedzi.
- Kod klienta wygląda jak wywoływanie lokalnej asynchronicznej funkcji, z użyciem
await
do oczekiwania na wynik, co dodatkowo ukrywa złożoność komunikacji sieciowej. - Nie ma potrzeby ręcznego konstruowania żądań HTTP ani analizowania odpowiedzi JSON.
Mimo że warstwa podstawowa może nadal używać HTTP/2 jako protokołu transportowego, ramy RPC (takie jak gRPC) zapewniają programistom warstwę abstrakcji, która sprawia, że zdalne wywołania wyglądają i działają jak lokalne wywołania funkcji.
Dlatego możemy zobaczyć, że większość sporów dotyczących "tylko POST" i API RESTful powinna w istocie dotyczyć tych dwóch stylów API: REST i RPC. Kluczowe jednak jest to, by uznać, że te dwa style mają swoje odpowiednie scenariusze zastosowania, a wybór powinien być oparty na konkretnej potrzebie projektu, a nie na preferencjach osobistych.
REST vs RPC: Brak absolutnej wyższości lub niższości
Teraz, gdy rozumiemy różnice między REST a RPC, spójrzmy na ich odpowiednie scenariusze zastosowania:
- REST jest odpowiedni dla:
- Aplikacje zorientowane na zasoby (takie jak systemy zarządzania treścią, platformy blogowe, witryny e-commerce)
- Scenariusze wymagające dobrego wsparcia dla cache (żądania GET są naturalnie cacheowalne)
- Projekty, które chcą korzystać z semantyki HTTP (takie jak używanie odpowiednich kodów statusu)
- API skierowane do publiczności, które wymagają dobrej wykrywalności i samoopisu
- RPC jest odpowiedni dla:
- Aplikacje zorientowane na działania (takie jak skomplikowane operacje przetwarzania danych, kontrola przepływu pracy)
- Systemy wymagające wysokiej wydajności i niskich opóźnień (takie jak systemy handlu w czasie rzeczywistym)
- Komunikacja między wewnętrznymi mikrousługami (które mogą wymagać bardziej elastycznego przekazywania parametrów)
- Gdy operacje nie mogą być prosto zmapowane na operacje CRUD (Utwórz, Odczytaj, Zaktualizuj, Usuń)
Wybór stylu powinien opierać się na Twoich konkretnych potrzebach. W niektórych przypadkach możesz nawet używać mieszanki tych dwóch stylów w tym samym systemie, aby sprostać wymaganiom różnych części.
Podsumowanie
- Istota projektowania API tkwi w jasności, spójności, rozwijalności i wydajności, a nie w trzymaniu się konkretnej metody lub stylu.
- Zarówno RESTful, jak i RPC, to dojrzałe paradygmaty projektowania API. Wybór między nimi powinien być oparty na wymaganiach projektu, a nie na osobistych preferencjach.
- Jeśli decydujesz się na użycie "tylko POST", projektuj swoje API zgodnie z stylem RPC. Podobnie jak RESTful, jest to powszechnie stosowana specyfikacja API w branży, ale należy ją stosować w odpowiednich scenariuszach.
- Nie daj się zwieść powierzchownym szczegółom technicznym. To, co naprawdę ma znaczenie, to czy Twoje API może efektywnie służyć użytkownikom i potrzebom biznesowym.
- Podczas projektowania API poświęć więcej czasu na myślenie o swoim modelu zasobów, logice biznesowej i potrzebach użytkowników, a nie na obsesję, którą metodę HTTP wybrać.
Skierujmy naszą uwagę z dala od tych bezsensownych argumentów i skupmy się na projektowaniu naprawdę doskonałych API. W końcu technologia służy do rozwiązywania problemów, a nie do ich tworzenia.