🇬🇧 Here is a link to English version.
W tym artykule opowiem, dlaczego stworzyłem projekt API Genie, oraz jak API Genie ma usprawnić proces tworzenia API REST-owych.
Przez ostatnich 10 lat pracuję z API webowymi. Pracowałem z GraphQL, RPC, SOAP-em itd., ale większość z nich była oparta o podejście REST.
Powiem szczerze: choć podoba mi się większość założeń podejścia REST, od kilku lat mam przekonanie, że rozwój owego podejścia zatrzymał się. Typowe problemy deweloperów tworzących API RESTowe nie zmieniają się od dawna, a odpowiedzi na większość z nich to cały czas “oto trzy alternatywy (wersjonowania), ale żadna nie rozwiązuje problemu w całości” albo “wiem, że to (agregowanie różnych zasobów w jednej końcówce) jest pragmatyczne, ale nie jest to zgodne z czystym RESTem”. Przy czym nikt owego “czystego RESTa” na żywo nie widział !
Stąd narodził się pomysł na stworzenie projektu API Genie.
W zamyśle API Genie ma:
W istocie, nic. Są natomiast kilka aspektów tego podejścia które nie zostały dobrze zrozumiane.
Po pierwsze, REST nie jest specyfikacją, tylko podejściem architektonicznym. Innymi słowy, zbiorem dość ogólnych zasad określających, jak należy tworzyć systemy rozproszone. Nie dostarcza żadnej formalnej specyfikacji, ani wytycznych, ani oprogramowania, które by wspomagało to podejście w codziennej pracy.
O ile te braki nie są problemem dla doświadczonych programistów (zawsze mogą wymyślić i poustawiać brakujące klocki, tak żeby pasowały do konkretnej sytuacji), to powodują sporo pytań ze strony młodszych kolegów. Poza tym, na pytania każdy może odpowiedzieć trochę inaczej, a to rodzi niezrozumienie (“w poprzednim projekcie robiliśmy inaczej”, albo “mi tamto podejście bardziej się podoba”) oraz sprowadza dyskusje techniczne na poziom emocjonalny. A to już osłabiają zaufanie do samej technologii.
Po drugie, część założeń RESTa dot. API, są dla większości z nas nieistotne. Roy Fielding (twórca koncepcji REST) pisał, że REST opisuje sposób tworzenia systemów rozproszonych które powinny ewoluować przez dziesieciolecia. Żeby umożliwić ewolucje systemów o tej skali, należałoby je odizolować (ang. decouple) od swoich klientów. Ponieważ w tamtych czasach nie było wtedy prostego sposobu do opisania kontraktów, postulował iż API RESTowe powinny być sterowalnymi przez przez klientów (be hypermedia driven). W praktyce to oznacza, ze:
Założenia te owszem są słuszne, tyle ze znacząco komplikują tworzenie oraz użycie REST API. A najważniejsze - zdecydowana większość developerów tego nie potrzebuje !
Potrzebuje natomiast innych cech:
Po trzecie, sztywna postawa Roy Fielding-a, który zacięcie bronił znaczenia skrótu REST. Według niego, API, które nie jest sterowane przez metadane (ang. - hypermedia-driven), nie jest RESTowe. Takie zerojedynkowe podejście powodowało niezrozumienie wśród deweloperów. To co my w końcu tworzymy - REST, czy jeszcze nie ? A jeśli nie, to jak go nazwać ? Tak trwało do momentu, w którym Leonard Richardson zaproponował model dojrzałości REST. Od tamtego czasu, używając skrótu RESTful, poniekąd udajemy że to jest “prawie REST”, ale cały czas nikt nie tworzy RESTowych API, które by były zgodne z oryginalną definicją.
Idea REST ma w sobie kilka bardzo pożytecznych założeń:
Pierwsze to skupianie się na zasobach oraz ich stanie. Zasób to odpowiednik obiektu lub encji, czyli czegoś, co ma swoją nazwę i ma sens w kontekście pewnej dziedziny. Podejście oparte na zasobach jest bardzo praktyczne, ponieważ w każdym, dosłownie każdym podejściu do projektowania musisz nazywać “cośki”, których używasz.
Owszem, REST dużo większą wagę przydziela stanowi zasobów aniżeli operacjom nad nimi. Zasadniczo mamy w REST 4 bardzo generyczne operacji, które skrótowo nazywamy CRUDem. Czasami taka generyczność nieco utrudnia pracę projektantów, szczególnie w podejściach jak np. DDD, które skupiają się na operacjach tak samo mocno jak na samych encjach. Omówię ten problem oraz jego rozwiązanie w kolejnych artykułach.
Drugie założenie (a nawet cała grupa) to używanie istniejącej infrastruktury WWW. Pomijając temat hyper mediów, serwery REST API są trywialne do stworzenia w dowolnym frameworku webowym. A to dlatego, że REST opiera się o infrastrukturę WWW . Używanie URL-i do identyfikacji zasobów - przecież to ten sam protokół, który stosujemy w przypadku stron internetowych. Używanie jednorodnego interfejsu do reprezentowania operacji nad zasobami ? A proszę bardzo, mamy metody HTTP oraz formularze HTTP, które z powodzeniem wykorzystują część tych metod. Cacheowanie ? Monitoring ? Oto masz gotowe oprogramowanie które to robi bardzo wydajnie.
API Genie ma na celu zmodernizowanie podejścia w którym tworzymy API oparte o zasoby (odmianą którego jest REST). Project ma trzy (równie ważne) cele:
A oto zasady którymi będę kierował się.
Na każde pytanie powinna być jedna jasna odpowiedź. Oprócz narzędzi API Genie ma na celu zebranie bazy wiedzy o dobrych praktykach oraz typowe przykłady API z różnych branż.
Opieramy się o pojęcie zasobów. Tutaj niczym nie różnimy się od REST.
Zasób (ang. - resource) jest czymś co ma nazwę oraz tożsamość. Employee
,
Credit
albo Onboarding
może być zasobem.
Do identyfikacji zasobów używamy URLi. Podobnie jak wyżej, zdecydowana większość zasobów jest identyfikowana za pomocą URLi. Jeśli któryś zasób występuje tylko i wyłącznie jako składowa innuch zasobów, może nie mieć dedykowanego URLa.
Używamy metod HTTP do reprezentowania operacji na zasobach. To jest ostatnia zasada zapożyczona z REST. Używanie standardowych metod HTTP pozwala na pełne wykorzystywanie semantyki oraz infrastruktury WWW oraz sparcia framework-ów.
Źródłem prawdy o API jest schema. Schema jest formalnym opisem API, który pozwala na oddzielenie kontraktu od implementacji. Posiadanie formalnej schemy daje wiele zalet, umożliwiając m.in. :
Kod jest pochodną schemy, i w większości powinien być generowany. Innymi słowy, jeśli kod może być wygenerowany na podstawie schemy, powinien zostać wygenerowany.
Generowanie ma wiele zalet, m.in.:
Owszem, stworzenie generatorów jest bardziej skomplikowanym zadaniem niż napisanie kontrolera RESTowego. Na szczęście ta dziedzina została dobrze opracowana, a sposób generowania kodu jest podobny dla większości śtechnologii.
Podejście do tworzenia API powinno być pragmatyczne, nie pedantyczne. API Genie ma rozwiązywać rzeczywiste problemy deweloperów. O ile trzymanie się zasad jest na ogół dobre, czasami należy robić odstępstwa. Owszem, należy je robić świadomie, ze zrozumieniem wpływu na pożądane cechy API, jak np. przystępność czy wydajność. No i należy pamiętać że wyjątki powinny być stosunkowo rzadkie (powiedzmy, 2% przypadków), żeby zostawać wyjątkami.
Należy utrzymywać kompatybilność z istniejącymi technologiami. Jestem tego zdania iż należy korzystać z doświadczenia poprzedników, a swój wysiłek aplikować na co już zostało zrobione. W taki sposób unikniemy wynalezienia koła na nowo oraz ogólnie przyśpieszymy postęp.
Narzędzia API Genie będą kompatybilne ze standardem OpenAPI 3.x oraz nowszymi. I tak zostanie. Aczkolwiek nie wykluczam dodania wsparcia innych standardów opisu.
Narzędzia powinny wspierać developerów w każdej czynności. W praktyce to oznacza iż narzędzia będą zintegrowane z edytorami, IDE oraz przeglądarkami (jako najczęściej używanymi klientami API). Powinny one być tak przystępne jak szczoteczka do zębów.
Należy umożliwiać stopniową adopcję podejścia schema first. Migracja z podejścia schema-less (jako najczęściej stosowanego obecnie) do podejścia schema driven może wymaga sporo czasu. Dlatego narzędzia API Genie będą umożliwiały stopniową migrację, tak żeby wdrożenie było przyjemniejsze.
Teraz do roboty.