
Jak trudne może być wersjonowanie API? Prawda jest taka, że nie jest to trudne, ale to, co jest trudne, to utrzymanie pewnej zdroworozsądkowej perspektywy, aby nie bezsensownie zbaczać w oszałamiającą liczbę wersji i podwersji stosowanych w dziesiątkach punktów końcowych API o niejasnych kompatybilnościach.
Business in a box.
Odkryj nasze rozwiązania.
Porozmawiaj z naszym zespołem sprzedaży
Złe zmiany! API Versioning dobre!
Jak każdy, kto zbudował lub regularnie korzysta z API, uświadamia sobie prędzej czy później, istotne zmiany są bardzo złe i mogą być bardzo poważną skazą na inaczej użytecznym API. Zmiana łamiąca to zmiana w zachowaniu API, która może złamać integrację użytkownika i spowodować wiele frustracji oraz utratę zaufania między dostawcą API a użytkownikiem. Zmiany łamiące wymagają wcześniejszego powiadomienia użytkowników (z towarzyszącymi przeprosinami) zamiast zmian, które po prostu się pojawiają, takich jak urocza nowa funkcja. Sposobem na uniknięcie tej frustracji jest wersjonowanie API z zapewnieniami od właściciela API, że nie będą wprowadzane żadne zaskakujące zmiany w ramach jednej wersji.
Więc jak trudno może być wersjonowanie API? Prawda jest taka, że to nie jest trudne, ale trudne jest utrzymanie pewnej zdrowej logiki, unikając niepotrzebnego rozszerzania do zawrotnej liczby wersji i podwersji zastosowanych w wielu punktach końcowych API z niejasnymi kompatybilnościami.
Wprowadziliśmy v1 API trzy lata temu i nie zdawaliśmy sobie sprawy, że będzie trwało do dziś. Jak więc udało nam się nadal dostarczać najlepsze API do dostarczania wiadomości e-mail przez ponad dwa lata, ale wciąż utrzymując tę samą wersję API? Chociaż istnieje wiele różnych opinii na temat wersjonowania REST APIs, mam nadzieję, że historia naszego skromnego, lecz potężnego v1 może cię poprowadzić na drodze do oświecenia w zakresie wersjonowania API.
REST Is Best
API Governance
Po wybraniu konwencji wersjonowania mieliśmy więcej pytań. Kiedy zmienilibyśmy wersję? Co to jest zmiana łamiąca? Czy rewizja całego API, czy tylko niektórych punktów końcowych? W SparkPost mamy wiele zespołów pracujących nad różnymi częściami naszego API. W ramach tych zespołów ludzie pracują nad różnymi punktami końcowymi w różnych momentach. Dlatego bardzo ważne jest, aby nasze API było spójne w użyciu konwencji. To było coś większego niż wersjonowanie.
Ustanowiliśmy grupę zarządzającą, w skład której wchodzą inżynierowie reprezentujący każdy zespół, członek zespołu zarządzania produktem oraz nasz CTO. Ta grupa jest odpowiedzialna za ustanawianie, dokumentowanie i egzekwowanie naszych konwencji API we wszystkich zespołach. Kanał API governance w Slack również okazuje się przydatny do żywych debat na ten temat.
Grupa zarządzająca zidentyfikowała szereg sposobów, w jakie można wprowadzić zmiany do API, które są korzystne dla użytkownika i nie stanowią zmiany łamiącej. Należą do nich:
Nowy zasób lub punkt końcowy API
Nowy opcjonalny parametr
Zmiana w niepublicznym punkcie końcowym API
Nowy opcjonalny klucz w ciele POST JSON
Nowy klucz zwracany w ciele odpowiedzi JSON
Natomiast zmiana łamiąca zawierała wszystko, co mogłoby zniszczyć integrację użytkownika, takie jak:
Nowy wymagany parametr
Nowy wymagany klucz w ciałach POST
Usunięcie istniejącego punktu końcowego
Usunięcie istniejącej metody żądania punktu końcowego
Znacząco różne wewnętrzne zachowanie wywołania API – takie jak zmiana w domyślnym zachowaniu.
The Big 1.0
Podczas gdy dokumentowaliśmy i omawialiśmy te konwencje, doszliśmy także do wniosku, że w interesie wszystkich (w tym nas samych!) jest unikanie wprowadzania zmian łamiących w API, ponieważ zarządzanie wieloma wersjami dodaje sporo obciążenia. Zdecydowaliśmy, że jest kilka rzeczy, które powinniśmy naprawić w naszym API przed zobowiązaniem się do wersji „v1”.
Wysłanie prostego e-maila wymagało zbyt wiele wysiłku. Aby „utrzymać proste rzeczy w prostocie”, zaktualizowaliśmy ciało żądania POST, aby zapewnić obsługę zarówno prostych, jak i złożonych przypadków użycia. Nowy format był również bardziej odporny na przyszłe zmiany. Po drugie, zajęliśmy się problemem z punktem końcowym Metrics. Ten punkt końcowy używał parametru „group_by”, który zmieniał format ciała odpowiedzi GET w taki sposób, że pierwszy klucz był wartością parametru group by. Nie wydawało się to zgodne z zasadami REST, więc rozdzieliliśmy każdy group by na osobny punkt końcowy. Na koniec skontrolowaliśmy każdy punkt końcowy i wprowadziliśmy drobne zmiany tu i tam, aby upewnić się, że są zgodne ze standardami.
Dokumentacja Accurate
Ważne jest posiadanie dokładnej i użytecznej dokumentacji API, aby uniknąć zmian, które mogą być zamierzone lub niezamierzone. Zdecydowaliśmy się na proste podejście do dokumentacji API, wykorzystując język Markdown zwany API Blueprint oraz zarządzać naszymi dokumentami w Github. Nasza społeczność przyczynia się i ulepsza te otwarte dokumenty. Utrzymujemy również niepubliczny zestaw dokumentów w Github dla wewnętrznych API i punktów końcowych.
Początkowo opublikowaliśmy nasze dokumenty w Apiary, świetnym narzędziu do prototypowania i publikacji dokumentacji API. Jednak osadzanie Apiary na naszej stronie nie działa na urządzeniach mobilnych, dlatego teraz używamy Jekyll do generowania statycznych dokumentów. Nasza najnowsza dokumentacja SparkPost API teraz ładuje się szybko i działa dobrze na urządzeniach mobilnych, co jest ważne dla developerów, którzy nie zawsze siedzą przy komputerze.
Separating Deployment from Release
Na początku nauczyliśmy się cennej sztuczki oddzielania wdrożenia od wydania. Dzięki temu możemy często wdrażać zmiany, gdy są gotowe, za pomocą ciągłego dostarczania i wdrażania, ale nie zawsze ogłaszamy je publicznie lub dokumentujemy w tym samym czasie. Nie jest niczym niezwykłym, że wdrażamy nowy punkt końcowy API lub ulepszenie istniejącego punktu końcowego API i używamy go w interfejsie użytkownika lub za pomocą narzędzi wewnętrznych zanim go publicznie udokumentujemy i wspieramy. W ten sposób możemy wprowadzać do niego drobne poprawki pod kątem użyteczności lub zgodności ze standardami, nie martwiąc się o wprowadzanie niechcianych zmian powodujących problemy. Gdy jesteśmy zadowoleni ze zmiany, dodajemy ją do naszej dokumentacji publicznej.
Cholera!
Uczciwie należy przyznać, że były chwile, kiedy nie sprostaliśmy naszym ideałom „braku zmian przełomowych” i warto z nich wyciągnąć naukę. Pewnego razu zdecydowaliśmy, że byłoby lepiej dla użytkowników, gdyby pewna właściwość domyślnie była ustawiona na true zamiast false. Po wdrożeniu zmiany otrzymaliśmy kilka skarg od użytkowników, ponieważ zachowanie zmieniło się niespodziewanie. Cofnęliśmy zmianę i dodaliśmy ustawienie na poziomie konta – zdecydowanie bardziej przyjazne dla użytkownika podejście.
Czasami jesteśmy kuszeni, by wprowadzać zmiany przełomowe w wyniku poprawek błędów. Jednak postanowiliśmy zostawić te idiosynkrazje w spokoju, zamiast ryzykować zepsucie integracji dla klientów w imię spójności.
Są rzadkie przypadki, kiedy podejmujemy poważną decyzję o wprowadzeniu zmiany przełomowej – na przykład wycofanie zasobu lub metody API – w interesie większej społeczności użytkowników oraz dopiero po potwierdzeniu, że ma to niewielki lub żaden wpływ na użytkowników. Na przykład celowo podjęliśmy decyzję o zmianie zachowania odpowiedzi Suppression API, ale dopiero po dokładnym rozważeniu korzyści i skutków dla społeczności oraz po starannym poinformowaniu naszych użytkowników o zmianie. Jednak nigdy nie wprowadzilibyśmy zmiany, która miałaby nawet zdalne prawdopodobieństwo bezpośredniego wpływu na wysyłkę produkcyjnego e-maila użytkownika.