Sytuacja kobiet w IT w 2024 roku
30.03.20207 min
Alexey Kuznetsov

Alexey KuznetsovSoftware DeveloperDekeo

Jak stworzyć dobre API

Prześledź ten przewodnik po tworzeniu API i zobacz, jakie czynniki przyczyniają się do stworzenia dobrego interfejsu, a co sprawia, że będzie się go źle używało.

Jak stworzyć dobre API

Ten artykuł może się przydać tym, którzy są w trakcie tworzenia swoich API lub parają się ulepszaniem istniejących. Poniższe rady wynikają z mojego własnego doświadczenia. Niektórych API nie cierpiałem, niektóre rozwinęły moją intuicję, a jeszcze inne pomogły mi w rozwinięciu zdolności paranormalnych. Były jeszcze takie, przez które śmiałem się jak maniak. Zaczynajmy!

Dobre API jest nudne. Bez wyjątków.

Postaraj się nie cudować, ponieważ zachowanie systemu powinno być takie same na każdym kroku. To działa w budowaniu punktu końcowego API oraz dla formatów danych wejściowych i wyjściowych. Potrzebujesz tych standardowych i nudnych komunikatów o błędach oraz nagłówków żądań i odpowiedzi. Pola z danymi zawsze powinny być w tych samych formatach. Wszystkie puste pola też powinny wyglądać tak samo. Programowanie Twojego API bardzo przypomina kłamanie: im bardziej jest wymyślne, tym łatwiej się w nim pogubić. Innymi słowy: nudne API to zadowoleni klienci. 

Tak na marginesie, powyższa rada jest też dobra przy projektowaniu całych systemów. 

Dokumentacja

Wszyscy wiemy, że trzeba dokumentować API, ale większość ludzi i tak tego nie robi. Jestem w stanie zrozumieć, że może nie być na to czasu, ale to decyduje, jak prezentuje się Twoje API. Dlatego warto odłożyć na bok ciekawsze wyzwania i zająć się dokumentacją. Oto, jak zrobić to dobrze:

  • Zawrzyj działające przykład żądań i odpowiedzi HTTP lub działający kod.
  • Dokumentacja powinna być formatowana tak konsekwentnie, jak API.
  • Podstawowe zasady API należy opisać jasno i szczegółowo.
  • Używaj takich frameworków API, jak Swagger, Apiary lub Postman.


Pamiętaj, że bez dobrej dokumentacji, używanie Twojego super API staje się układaniem tysiąca puzzli. 

Dokumentacja Postman API


Obsługa błędów

Nawet jeśli API ma słabą dokumentację, można zajść daleko, polegając jedynie na dobrych komunikatach o błędach. Z reguły dokładne i jasne komunikaty o błędach naprawdę mają znaczenie dla wygody użytkownika. Nawet z punktu widzenia osoby, która tworzy API, pozwalają one na odważniejszą pracę i szybsze reagowanie na błędy.

Zły błąd:

HTTP/1.1 422 Unprocessable Entity
{
“error”: Invalid Attribute
}


Dobry błąd:

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/vnd.api+json
{
"errors": [
{
"status": "422",
"source": { "pointer": "/data/attributes/first-name" },
"title": "Invalid Attribute",
"details": "First name must contain min three chars."
}
]
}

Autoryzacja

Każdy typ autoryzacji jest przydatny, jeśli jest znormalizowany. Nie mieszaj tam za bardzo. Praca nad procesami autoryzacji staje się prawdziwym problemem, jeśli są one niestandardowe lub mechanizmy są zbyt słabe. Weź przykład OAuth: generował on refresh-token przy każdej aktualizacji access-tokena i wymagał przypisania momentu wygaśnięcia access tokena.

To zbyt wiele, jak dla mnie. Po pierwsze, pozwól swoim użytkownikom zdecydować, jakiego poziomu zabezpieczeń potrzebują oraz, jeśli to możliwe, zezwalaj na niewygasające tokeny. Po drugie, nie komplikuj procesu. Wiele dobrych API używa statycznych refresh tokenów. Bezpieczeństwo to nie to samo co komplikacja. 

Formaty danych

Nawet nie myśl o tworzeniu nowych formatów danych! Widziałem API z niestandardowymi formatami danych i były do bani. Parsowanie i analiza unikatowego formatu znacznie spowalnia i utrudnia pracę. Wiem, że trudno jest stłumić swoją kreatywność, zwłaszcza gdy chodzi o tworzenie niestandardowych rzeczy, ale musicie się temu oprzeć. Mamy już JSON, XML i całą resztę, prawda? To wystarczy.

Powinniście skorzystać z gotowych specyfikacji, takich jak JSON API. Stripe, Braintree i wiele innych firm z powodzeniem z niego korzysta. JSON wygląda dobrze, ma łatwy w użyciu ustrukturyzowany format danych, a specyfikacja JSON API jest ogólnie dobrze przemyślana.

Nie obsługuj również wielu formatów danych. Klienci na ogół nie dbają o to, jakiego standardowego formatu danych używają, ponieważ wszystkie języki programowania i technologie obsługują już formatowanie i parsowanie każdego z nich. Uwzględnienie wielu formatów spowalnia niepotrzebnie API i komplikuje utrzymanie dobrej dokumentacji.

Używaj kodów odpowiedzi HTTP

Otrzymanie wewnętrznych błędów API ze statusem HTTP 200 może być dla programistów mylące. To naprawdę spowalnia poprawne zakodowanie integracji. W wielu przypadkach kody odpowiedzi HTTP mogą pełnić rolę komunikatu o błędzie. Oto przykłady:

200 (OK) — success, handle responded data.
500 (Internal Server Error) — something went wrong, ask for API system technical support.
400 (Bad Request) — wrong API request, check documentation.
401 (Unauthorized) — wrong client credentials, recheck them or if API key token has expired, then refresh.
403 (Forbidden) — unpermitted action, current user does not have enough access rights.
404 (Not Found) — record not found, maybe it doesn’t exist anymore or wrong record ID was used.
405 (Method Not Allowed) — this API method is not allowed anymore.
406 (Not Acceptable) — not acceptable action, probably from attempt to save invalid data.


Aby dowiedzieć się więcej o reszcie kodów, sprawdź tę stronę na Wikipedii, a zapewniam Cię, że znajdziesz dla siebie odpowiedni komunikat.

Content-Type

To prosta rada: typ treści zawsze powinien być taki sam. Pomaga to zachować spójność architektury klienta oraz przyspiesza i upraszcza proces programowania. Unikaj również dopuszczania kilku obsługiwanych typów treści dla punktu końcowego. Może to zmylić programistów, którzy używają tego endpointu. Na przykład, Twój punkt końcowy „A” działa dobrze, ale punkt końcowy „B” zwraca Bad Request, pomimo tego, że używasz go w ten sam sposób. Zmiana typu treści nie wydaje się oczywistym rozwiązaniem.

Struktura obiektu

Z perspektywy klienta, warto wiedzieć, jakie pola ma dany typ obiektu. Idealnie jest, jeśli API ma specjalny punkt końcowy, który zwraca pełne mapowanie pól dla danego typu obiektu. W przeciwnym razie warto jest się przynajmniej upewnić, że getter listy obiektów lub obiektu zwraca każde pole, nawet jeśli jest ono puste. Nie potrzebujemy tutaj dynamizmu i zwięzłości.

{
"id": "9c7fd1e5-97f0-4b6a-979c-1d7adf5bda16",
"email": "[email protected]",
"firstname": "John",
"lastname": "Smith",
"timezone": null,
"phone_code": "RU",
"phone": null,
"created_at": "2018-03-27T05:40:31.929Z",
"updated_at": "2018-04-08T09:24:39.683Z",
"citizenship": null
}

Paginacja

Kiedy pracowałem nad konektorem API znanego systemu CRM, zdałem sobie sprawę, że nie ma tam żadnego rekordu paginacji. Od wsparcia technicznego dowiedziałem się, że „niestety tego nie zawarliśmy, ale to dobry pomysł do wdrożenia”. Nie mogłem w to uwierzyć. Wszyscy dobrze wiecie, dlaczego nie możemy załadować wszystkich danych naraz, dlatego pozwólcie, że wyjaśnię Wam, dlaczego paginacja jest tutaj idealna:

  • Kontrolowanie rozmiaru strony paginacji jest przydatne, ponieważ umożliwia użytkownikom wybór między ilością a jakością żądań. 
  • Paginacja posiada meta informacje, aby zorientować się, ile mamy podsumowań rekordów. W przypadku ładowania wszystkich z nich pomaga zrozumieć postęp. Ponadto, policzenie wszystkich rekordów nie wymaga od nas ładowania wszystkich stron. Nie marnujmy czasu ani pieniędzy.
  • Ma jasne i stałe nazewnictwo swoich zmiennych, na przykład: page_number - aktualny numer strony; page_size - rozmiar strony; pages_total_count - całkowita liczba stron.

Pliki i obrazy

Może się to wydawać oczywiste, ale nie należy umieszczać plików ani obrazów w danych wewnątrz odpowiedzi. O wiele lepiej jest zwrócić tymczasowy link do pliku.

Czas i data

Określenie strefy czasowej, której używamy, jest naprawdę ważne. Może to być część formatu czasu lub po prostu fraza w dokumentacji. Kwestia poprawnego używania stref czasowych zasługuje na osobny artykuł, ale już teraz możesz zwrócić datę w sekundach określonych jako timestamp, ponieważ czas unixowy jest w UTC. Każdy klient może to wykorzystać, aby poprawnie sformatować czas i użyć odpowiedniej strefy czasowej.

{
...
"created_at" => article.created_at.utc.to_i
}.to_json
#=> { ..., created_at: 1523556863 }

Informacje o wymaganej płatności

Należy użyć kodów odpowiedzi HTTP, aby poinformować klienta, gdy spróbuje skorzystać z punktów końcowych wymagających płatności, podczas gdy ma darmowy lub niewystarczający plan. Czasami w takim przypadku trudno jest zrozumieć, co poszło nie tak. Sugeruję tutaj użycie kodu odpowiedzi HTTP 402 Payment Required. Możesz wybrać każdy inny kod, o ile wszystko jest jasne. Dokumentacja API powinna również jasno opisać warunki użytkowania płatnych endpointów.

Limity w API

Jeśli programowo ograniczysz liczbę żądań w API, warto jest mieć jasny komunikat o błędzie przy osiągnięciu limitu. Idealny byłby do tego specjalny punkt końcowy z tymi informacjami.

Twoi klienci nie powinni sami liczyć żądań API, bo to Ty masz te liczby. Dobrze jest renderować informacje o dostępnych wywołaniach API w nagłówkach odpowiedzi HTTP. Na przykład:

X-RateLimit-Limit - Request limit per hour
X-RateLimit-Remaining - The number of requests left for the time window


Przykład z ZohoCRM

Aspekt logiczny

Rozwijając swoje API, dobrze jest postawić się na miejscu klienta. Możesz sobie bardzo wtedy pomóc. Na przykład, w niektórych API widziałem, że po dwukrotnym usunięciu rekordu za każdym razem otrzymasz tę samą odpowiedź. To niedobrze, ponieważ Twojemu klientowi wydaje się wtedy, że usunął go ponownie lub usunął inny rekord. Co powinno się zrobić to zwrócić kod odpowiedzi HTTP 404, jeśli rekord został już usunięty. Pomoże to klientom w zauważeniu swoich błędów.

Kolejna obserwacja

Dziwne punkty końcowe API mogą zwiastować coś niedobrego w Twoim projekcie. Zamiast tworzyć fasady i adaptery, zrób sobie przerwę i rozejrzyj się przez chwilę. Bardzo możliwe, że zobaczysz dobrą okazję do refaktoryzacji i upieczenia dwóch pieczeni na jednym ogniu: uprościsz swoje API i ulepszysz strukturę projektu.

Posłowie

Chciałbym podziękować wszystkim tym, którzy tworzą wysokiej jakości i łatwe w użyciu API. Wiem, że często robicie to w zgodzie z własnym sumieniem i poczuciem estetyki. Na pierwszy rzut oka, korzyści płynące z powyższych rad nie są aż takie oczywiste, ale przynoszą długofalowe efekty i zapewniają lojalność klientów. Wszystkiego najlepszego dla tych, którzy się tym trudzą!

Oryginał tekstu w języu angielskim przeczytasz tutaj.

<p>Loading...</p>