Wersjonowanie REST API: URL, nagłówek czy query, co pasuje
5 min czytania
Wersjonowanie REST API to sposób, w jaki API mówi wywołującemu, którego kontraktu używa żądanie, żeby serwer mógł zmienić kontrakt bez łamania wywołujących, którzy się nie przenieśli. Wersja może trafić w trzy miejsca: ścieżkę URL (/v2/orders), nagłówek żądania (Accept: application/vnd.acme.v2+json albo własny Api-Version: 2026-10-01) lub parametr zapytania (/orders?version=2). Ścieżka jest najczęstsza, bo widać ją wszędzie, nagłówek jest najczystszy dla URL, a query string to ten wybór, którego większość zespołów żałuje. Co pasuje, zależy od tego, kim są wasi wywołujący i jak planujecie mówić im o zmianach.
| Gdzie żyje wersja | Przykład | Kto ją widzi | Cache’owalne domyślnie | Kto używa |
|---|---|---|---|---|
| Ścieżka URL | GET /v2/orders | Każdy log, link, proxy i przeglądarka | Tak | Twitter, Shopify, większość publicznych API |
| Własny nagłówek | Api-Version: 2026-10-01 | Tylko klienci, którzy go ustawiają | Z Vary: Api-Version | Stripe (Stripe-Version), GitHub (X-GitHub-Api-Version) |
| Nagłówek Accept | Accept: application/vnd.acme.v2+json | Tylko klienci, którzy go ustawiają | Z Vary: Accept | Typy mediów GitHuba, część API enterprise |
| Parametr zapytania | GET /orders?api-version=2 | Logi i linki, wymieszana z filtrami | Tak, ale zaśmieca klucze cache’a | REST API Azure |
| Brak wersji | GET /orders plus wyłącznie zmiany addytywne | Nikt | Tak | API wewnętrzne i w stylu GraphQL |
Czym są v1 i v2 w REST API?
v1 i v2 to etykiety dwóch wersji kontraktu API: te same zasoby, dostępne pod różnymi ścieżkami, gdzie v2 może zmieniać nazwy pól, zmieniać typy, usuwać endpointy lub zmieniać kształt błędów, na których polegają wywołujący v1. Żądanie do /v1/orders dostaje stary kształt tak długo, jak v1 jest wspierane; żądanie do /v2/orders dostaje nowy. Numer to obietnica zgodności i to ta obietnica czyni go użytecznym. Podbijanie go przy każdym wydaniu zamienia etykietę w szum.
Większość API potrzebuje nowej wersji głównej tylko dla zmiany, która łamie istniejących wywołujących. Dodanie pola, nowego endpointu lub nowego opcjonalnego parametru może wyjść pod bieżącą wersją, bo dobrze napisany klient ignoruje to, czego nie zna. Kiedy wersjonować API i co robić zamiast tego omawia tę decyzję; ten artykuł jest o tym, gdzie w wersjonowaniu REST API trafia wersja, gdy już zdecydowaliście ją podbić.
Czy wersjonowanie REST API powinno być w URL, czy w nagłówku?
Umieśćcie je w URL, jeśli wśród waszych wywołujących są ludzie wpisujący żądania w przeglądarce, kopiujący przykłady z dokumentacji lub czytający logi; umieśćcie je w nagłówku, jeśli chcecie jednego stabilnego URL na zasób, a wasi wywołujący to wyłącznie SDK lub kod, który kontrolujecie. Ścieżka URL jest jawna jak nic innego: zgłoszenie do supportu z linią żądania już mówi wam, która to wersja. Nagłówek trzeba ustawić w każdym żądaniu, jest niewidoczny w linku i łatwo go zgubić na proxy, dlatego API wersjonowane nagłówkiem zawsze definiują wartość domyślną dla żądań, które go nie wysyłają.
Podejście z nagłówkiem ma jedną realną zaletę poza schludnymi URL-ami: oddziela tożsamość zasobu od jego reprezentacji, czyli tak, jak zaprojektowano HTTP. RFC 9110 opisuje negocjację treści przez Accept, a typ mediów taki jak application/vnd.github.v3+json to wersja wyrażona w ten sposób. W praktyce czystość projektu znaczy mniej niż to, czy wasi wywołujący pamiętają o wysłaniu nagłówka.
Jak działa wersjonowanie datami?
Zamiast v1 i v2 wersja jest datą, a każda zmiana łamiąca kompatybilność dostaje nową datę. Wywołujący przypina datę, z którą się zintegrował, zwykle raz na poziomie konta, i zachowuje to zachowanie, dopóki sam nie zdecyduje się przenieść. Nagłówek Stripe-Version Stripe i X-GitHub-Api-Version GitHuba działają właśnie tak.
Kompromis leży w implementacji. Każda zmiana łamiąca kompatybilność staje się małą warstwą transformacji, która tłumaczy między przypiętą datą a bieżącym kształtem, a serwer je piętrzy: żądanie przypięte dwa lata wstecz przechodzi przez każdą zmianę od tamtej pory. To cięższe do zbudowania niż druga kopia handlerów i nagradza API, które zmienia się rzadko. Zespoły wydające zmianę łamiącą co miesiąc kończą z dziesiątkami transformacji. Wersjonowanie API Stripe patrzy na ten model od strony wywołującego, w tym na to, co musi nieść changelog.
Dlaczego wersjonowanie w query stringu jest odradzane?
Bo miesza kontrakt z filtrami. /orders?status=open&api-version=2 sprawia, że wersja wygląda jak opcjonalne doprecyzowanie, a nie rzecz decydująca o kształcie każdego pola w odpowiedzi. To także najłatwiejsza do przypadkowego zgubienia, bo query stringi są przebudowywane przez biblioteki klienckie, obcinane przez część proxy i edytowane ręcznie przez ludzi. Własne wytyczne Microsoftu dotyczące projektowania REST API dokumentują formę z parametrem zapytania, której używa Azure, a ekosystem generowanych SDK wokół niej jest tym, co czyni to wykonalnym; bez tych narzędzi wywołujący, który zapomni parametru, po cichu dostaje wersję domyślną.
Co dzieje się ze starą wersją?
Działa dalej, z datą, w której przestaje. Sens wersjonowania to pozwolić wywołującym przenosić się według własnego harmonogramu, a to prawda tylko wtedy, gdy stara wersja zostaje dostępna wystarczająco długo, by zdążyli, i gdy wiedzą, kiedy się kończy. Wytyczne Google dotyczące wersjonowania API opisują cykl życia, którego używa dla własnych API: stabilna wersja jest wspierana do opublikowanej daty deprecjacji, a zamiennik jest dostępny przez całe okno deprecjacji.
Ogłoszenie to część, którą większość zespołów buduje za słabo. Nowa ścieżka lub nagłówek przydają się tylko wywołującym, którzy wiedzą, że istnieją, wiedzą, co się zmieniło, i wiedzą, kiedy v1 znika. To trzy fakty i każdy potrzebuje swojego miejsca: datowany wpis w changelogu API z różnicami na poziomie pól, powiadomienie o deprecjacji, które podaje datę końca, oraz przewodnik migracji, który przechodzi przez każdą zmianę dla wywołującego wciąż na starej wersji. Wygaszanie wersji API omawia ostatni krok, w tym nagłówek Sunset, który pozwala klientowi odkryć datę w każdej odpowiedzi.
Czy można całkiem uniknąć wersjonowania REST API?
Tak, tak długo, jak każda zmiana jest addytywna. Dodawajcie pola, nigdy ich nie usuwajcie ani nie zmieniajcie nazw; dodawajcie endpointy, nigdy nie zmieniajcie tego, co zwraca istniejący; przyjmujcie nowe opcjonalne parametry, nigdy nie zmieniajcie znaczenia starego. Wiele wewnętrznych API działa latami na samej tej zasadzie i to zasada, której schematy GraphQL trzymają się z założenia. Kosztem jest kontrakt, który tylko rośnie, ze zdeprecjonowanymi polami, które muszą zostać, bo ktoś, gdzieś, nadal je czyta.
Gdy zmiana addytywna jest niemożliwa, narzędziem jest wersja. Wybór między ścieżką, nagłówkiem i datą decyduje, co widzą wywołujący i jak ogłaszana jest zmiana; stałe jest to, że zmianę trzeba zapisać gdzieś, gdzie wywołujący ją przeczyta. Dla API z zewnętrznymi wywołującymi tym miejscem jest changelog, a artykuł o zmianach łamiących kompatybilność omawia, co się za taką liczy.
FAQ
Jaki jest najlepszy sposób wersjonowania REST API? Wersja główna w ścieżce URL jest najszerzej rozumiana i najtrudniejsza do zepsucia, co czyni ją domyślnym wyborem dla publicznego API. Wersja w nagłówku utrzymuje stabilne URL-e i pasuje do API opartych na SDK; datowany nagłówek pasuje do API, które zmieniają się rzadko i chcą, by wywołujący przypinali zachowanie.
Czym jest v1 w URL API?
To pierwsza wersja główna kontraktu API. Żądaniom do /v1/... obiecany jest kształt udokumentowany dla wersji 1, nawet gdy istnieje już /v2/ z innymi polami lub zachowaniem.
Czy potrzebuję nowej wersji API przy każdej zmianie? Nie. Zmiany addytywne, takie jak nowe pola, endpointy i opcjonalne parametry, mogą wyjść pod istniejącą wersją. Tylko zmiana, która łamie istniejących wywołujących, potrzebuje nowej.
Jak długo powinna być wspierana stara wersja API? Wystarczająco długo, by wywołujący zdążyli migrować, co dla publicznego API to zwykle sześć do dwunastu miesięcy od udostępnienia zamiennika, z datą opublikowaną w ogłoszeniu i powtórzoną w powiadomieniu o deprecjacji.
Twierdzenia techniczne w tym artykule nie zostały niezależnie zweryfikowane. Jeśli coś się nie zgadza, daj nam znać, a poprawimy to.