From d27786042d9d2bdc20d6e9d3929b627734b0a235 Mon Sep 17 00:00:00 2001 From: Honza Javorek Date: Sun, 14 Sep 2014 18:29:49 +0200 Subject: [PATCH] =?UTF-8?q?Verzov=C3=A1n=C3=AD.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- obr/fielding-tweet.png | Bin 0 -> 39648 bytes verzovani.md | 134 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100644 obr/fielding-tweet.png create mode 100644 verzovani.md diff --git a/obr/fielding-tweet.png b/obr/fielding-tweet.png new file mode 100644 index 0000000000000000000000000000000000000000..da038b0cbe04cf8a15dfa68486e9b00975924d85 GIT binary patch literal 39648 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 literal 0 HcmV?d00001 diff --git a/verzovani.md b/verzovani.md new file mode 100644 index 0000000..86af619 --- /dev/null +++ b/verzovani.md @@ -0,0 +1,134 @@ +# Verzování + +Věčná otázka: Jak verzovat API? Pomocí prefixu v URL? Pomocí HTTP hlaviček? Aby to nebylo jednoduché, já osobně nejsem fanouškem ani jedné z oněch dvou tradičně diskutovaných metod. + +## Co je verzování? + +1. Mám existující API a rozhodl jsem se, že jej kompletně přebuduji a představím úplně nové rozhraní, ale pro tentýž účel. + +2. Mám existující API a potřebuji do něj uvést nějakou změnu. + +## Přebudováváme celé API + +Pro tento případ mám jedinou radu: Jedná se technicky o úplně jiné API a měli byste ho dát na jinou (sub)doménu. Provozujete-li API na adrese `api.example.com`, tak zřiďte např. `api-v2.example.com`. Technicky je to samozřejmě proveditelné přes URL prefixy jako `api.example.com/v2/`, ale v tomto případě takový postup přináší do budoucna jen problémy. + +Tvoříte totiž v podstatě úplně novou aplikaci a v kontextu HTTP se nejlépe s aplikacemi pracuje při dodržování pravidla, že jedna (sub)doména představuje jednu samostatnou věc. Třeba ji píšete ve stejném programovacím jazyce a na stejném frameworku, ale do budoucna to nemusí být pravda. Rozhodnete se udělat třetí verzi na bázi [WebSocketů](https://en.wikipedia.org/wiki/WebSocket), napsat ji v [node.js](http://nodejs.org/) nebo budete chtít jen použít jiné HTTPS certifikáty a hned máte velký problém. + +## Děláme zpětně nekompatibilní změny + +Pokud přidáváme novou funkčnost, většinou se o verzování nezajímáme - prostě ji přidáme a zdokumentujeme. Problém nastává, odebíráme-li funkčnost, nebo pokud děláme změny, jež jsou zpětně nekompatibilní a rozbily by existující klienty. + +O čem je vlastně tento typ verzování? Máme nějakou věc - třeba auto. Tu věc můžeme na internetu nějak reprezentovat. Tato reprezentace má nějakou svou adresu, URL. Reprezentace může být v různých formátech - v `text/html` jako webová stránka, v `image/png` jako fotografie nebo třeba v `application/json` jako odpověď v API. Verzování je o tom, že ten formát měníme a potřebujeme ho v čase odlišit. Různé verze jsou tedy jen různými formáty, které jsou si čirou náhodou nějak podobné. + +Máme tři možnosti jak verzování řešit: + +- Dát verzi do URL, +- dát verzi do HTTP hlaviček, +- vyhýbat se verzování jako čert kříži, + +nebo kombinovat výše uvedené. + +### URL prefix (např. `api.example.com/v1/...`), parametr (`/resource?v=1`) + +Toto je nejoblíbenější řešení v praxi a zřejmě nejzatracovanější mezi odborníky (ne, nemám průzkum, který bych zde citoval a je to jen můj dojem). Problém s touto metodou je hlavně v tom, že jde docela dost proti celé myšlence REST (ačkoli někteří obhájci prefixu by i toto dokázali vyvrátit). Já si myslím, že s touto metodou nemáte moc šancí vytvořit postupně se vyvíjející API - jste svázáni tím, co vám umožní URL a přesměrovávání v rámci HTTP. + +Mechanismus URI/URL je určen k identifikaci/adresaci něčeho. Tím jak je lidem na očích ale nejspíš svádí k neustálému "přetěžování" - nalepujeme na něj věci, které do něj nepatří. `/v1` je tudíž asi stejně špatně, jako `/resource?format=xml`. URL je cesta k něčemu, co by klient chtěl a ne popis toho, jak by klient nějakou věc chtěl. Osobně si myslím, že verze do adresy nepatří, jedná se o její mrzačení a nepochopení principů REST. + +#### Odkazovatelná URL + +Hodně lidí kritizuje řešení HTTP hlavičkami z toho důvodu, že je nelze snadno zanášet do dokumentací nebo vyzkoušet v prohlížeči. Já bych na to asi odpověděl, že by se měl člověk smířit s tím, že HTTP je prostě URL **a** hlavičky **a** tělo zprávy a že je to dost chabý důvod, protože pak stačí jeden `POST` s daty a stejně odkaz udělat nelze. + +Každopádně je to ale řešitelný problém - vaše API může fungovat na základě content negotiation a přitom poskytovat speciální parametry v URL, které se do tohoto mechanismu zapojí a vynutí nějakou z možností pro potřeby příkladů nebo ladění. Tyto parametry můžete udělat nejen pro verzi (`?_v=3`), ale i pro formát (`?_format=json` jako suplování `Accept`), jazyk (`?_lang=cs` jako suplování `Accept-Language`) nebo i metodu, budete-li chtít - často se takto implementuje podpora pro `PUT` a `DELETE` do HTML, které má ve formulářích jen `GET` a `POST` (např. `?_method=delete`). + +Jak jste si asi na mých příkladech všimli, je dobré tyto speciální parametry nějak odlišit od běžných - třeba podtržítkem. Zabráníte kolizím s běžnými parametry a zároveň dáváte tvůrci klienta signál, že se jedná o něco nestandardního. + +#### Obsluhování neexistujících URL + +[URL bychom měnit neměli.](http://weblog.jakpsatweb.cz/d/1333060980-tri-zasady-pro-tvorbu-dobrych-seo-url.html) Když už to děláme, měli bychom alespoň ošetřit případy, kdy se někdo na starou adresu odkáže. + +Verzujeme-li v URL, nastane okamžik, kdy chceme starou verzi API přestat provozovat nebo kdy např. nechceme některé části nového API implementovat znovu, jelikož se nezměnily, ale nejraději bychom je přesměrovali na existující verzi. K tomu nám poslouží HTTP odpověď `410 Gone` nebo [3xx kódy](https://cs.wikipedia.org/wiki/Stavov%C3%A9_k%C3%B3dy_HTTP#3xx_Redirect). + +Pozor na přesměrování - většina klientských knihoven jej implementuje automaticky a tak byste měli přesměrovávat opravdu pouze na zcela ekvivalentní odpovědi. Přesměrování v praxi moc nefunguje jako informace "podobnou věc v nové verzi nalezneš tady", ale spíš "toto je odteď tady", takže nesprávné použití by rozbilo klienty. Raději bych pro nasměrování na novou verzi použil `410 Gone` s tělem, v němž bude ve srozumitelném formátu (máte-li JSON API, tak JSON, ale klidně i HTML) vysvětleno, kam se daná věc poděla a jak nejlépe opravit klienta, aby se ze změny vzpamatoval. + +### HTTP hlavičky (např. `application/vnd.company.example-v1+json`) + +Tohle dělá např. GitHub ve svém [API](https://developer.github.com/v3/#current-version). V zásadě se jedná o to, že využijete [content negotiation](content-negotiation.md) k tomu, abyste si s klientem domluvili správný formát odpovědi. + +Zdokumentujete různé formáty odpovědí na jednotlivé požadavky a přidělíte jim ["vendor" typy](http://tools.ietf.org/html/rfc6838#section-3.2) (hlavička `Content-Type`), jako třeba `application/vnd.github.v2+json` nebo `application/vnd.github.v3+json`. Jeden z těchto formátů budete vracet jako výchozí. + +Verzi můžete mimochodem dát také do parametru: `vnd.example-com.foo+json; version=1.0`, což je dle mého názoru hezčí a lépe to ilustruje, že jde jen o jiné stádium vývoje téhož typu. + +#### Formát výchozí odpovědi + +Pozor! Pokud nechcete při uvední nových verzí API rozbít staré klienty, musíte logicky jako výchozí vracet ten úplně nejstarší typ, se kterým jste API spustili. Jenže klient pak zase bude muset vždy uvést `Accept` hlavičku, což je nepříjemné. Řešením je nejspíš na přechodnou dobu vždy vracet jako výchozí tu původní verzi a po nějaké době a osvětě mezi tvůrci klientů přistoupit k tomu, že stará verze bude už jen na vyžádání hlavičkou, zatímco nová bude nově vždy vrácena jako výchozí. + +#### Zpracování požadavku na již nepodporovaný formát + +Máte dvě možnosti, jak na serveru zpracovat požadavek s `Accept`, které prosí o vámi nepodporovaný typ. (Schválně jsem použil slovo prosí, jelikož content negotiation v zásadě funguje na principu toho, že server by měl preferenci klienta respektovat, ale vlastně vůbec nemusí.) + +1. Budete hlavičku ignorovat a vrátíte výchozí formát (se správným `Content-Type`, aby klient mohl rozeznat, že nedostal to, co chtěl). +2. Zamítnete odpověď s HTTP chybou `406 Not Acceptable`, která [znamená](https://cs.wikipedia.org/wiki/Stavov%C3%A9_k%C3%B3dy_HTTP#4xx_Client_Error) "Server může generovat pouze odpověď, která není klientem podporována." + +Co použijete je na vás - závisí to od vašeho případu použití, od stavu vašich klientů, apod. + +### Třetí "možnost": vůbec neverzovat! + +Jak to jednou [Roy Fielding](https://en.wikipedia.org/wiki/Roy_Fielding) [napsal na Twitter](https://twitter.com/fielding/status/376835835670167552): + +![tweet](obr/fielding-tweet.png) + +Tedy něco jako... + +> Důvodem proč tvořit opravdová REST API je "evolvability", tedy možnost jejich postupného vývoje. Dát do URL něco jako "v1" je prostředníček uživatelům vašeho API a poukazuje na RPC/HTTP, ne na REST. + +### Co je "evolvability"? + +Třeba jednou přijdu na to, jak toto slovo přeložit, ale zatím onen čas nepřišel :-) Tím spíše je chybějící překlad bolestivější, když je toto jedna z hlavních výhod [hypermedia API](hypermedia.md). Nejlepší co mě napadlo je asi *rozvíjitelnost*. + +Jedná se ve zkratce o to, že API je možné navrhnout tak, aby bylo možné jej v čase vyvíjet a přitom nerozbíjet existující klienty. Trik je především v tom, že klient najde přímo v odpovědi ze serveru instrukce jak se má dále dotazovat, pokud chce udělat to či ono. Sám je potom sestrojen dostatečně volně tak, že dokáže zmíněné instrukce následovat. + +Bystrým čtenářům to nejspíš něco připomene - přesně tímto způsobem dnes fungují webové stránky. Také je to HTTP, akorát odpovědi ze serveru jsou ve formátu HTML a klientem je většinou prohlížeč. Zmíněné instrukce jsou pak představovány hlavně odkazy `` a formuláři `
`. Klient v odpovědi vyhledá formulář, vyplní jej, odešle na server a je to. Žádná [dokumentace](dokumentace.md), žádné návody. + +Řeknete si nejspíš, že za prohlížečem je člověk, ale u API je to program a ten se neumí sám rozhodovat. Ne tak docela - mobilní aplikace může být stejně tak dobře řízena člověkem a pouze mu nabízet možnosti ze serveru, jako to dělá prohlížeč. A pokud jste si někdy napsali scraper, který následoval odkazy nebo odesílal formuláře, nejspíš to ani nevíte a vytvořili jste docela obstojného hypermedia klienta pro API s názvem internet. + +REST API **je** webová stránka a webová stránka **je** REST API. Když si vypůjčím slova R. Fieldinga: Kdy naposledy jste viděli číslo verze na webové stránce? + +Pro úvod by to nejspíš stačilo - pokud vás tento směr zajímá více, prozkoumejte [tuto část Jak psát API](hypermedia.md). + +## Externí zdroje + +### [Jeremy H: Versioning and Types in REST/HTTP API Resources](http://thereisnorightway.blogspot.cz/2011/02/versioning-and-types-in-resthttp-api.html) + +Jeremy na blogu s příznačným názvem "There Is No Right Way" rozebírá možnosti verzování API, jejich výhody a nevýhody. + +### [Roy Fielding: EVOLVE'13 | Keynote](http://www.slideshare.net/evolve_conference/201308-fielding-evolve) + +Prezentace R. Fieldinga, na které vysvětluje "evolvability" jako řešení na problém verzování API. + +### [Troy Hunt: Your API versioning is wrong, which is why I decided to do it 3 different wrong ways](http://www.troyhunt.com/2014/02/your-api-versioning-is-wrong-which-is.html) + +Troy píše, že každá možnost je dobrá pro jiný případ použití. Doporučuje je nakombinovat. + +### [Robbie Clutton: API Versioning](http://pivotallabs.com/api-versioning/) + +Robbie rozebírá obě možnosti i z pohledu implementace v Ruby. Dochází k závěru, že hlavičky jsou sice fajn, ale z uživatelského hlediska jsou nepraktické, protože na takový požadavek nelze snadno odkázat. Zamýšlí se tedy nad tím, zda by nebylo lepší obě varianty kombinovat. + +### [Vinay Sahni: Best Practices for Designing a Pragmatic RESTful API](http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api#versioning) + +Vinay doporučuje verzování v URL. + +### [StackOverflow: Best practices for API versioning?](https://stackoverflow.com/questions/389169/best-practices-for-api-versioning) + +Velmi odkazovaná diskuse na StackOverflow, která přesně ilustruje, jak se názory na toto téma mezi lidmi liší :-) + +### [Tim Wood: How are REST APIs versioned?](http://www.lexicalscope.com/blog/2012/03/12/how-are-rest-apis-versioned/) + +Přehled toho, jak verzování implementují v různých existujících API. + +### [Steve Klabnik: Nobody Understands REST or HTTP](http://blog.steveklabnik.com/posts/2011-07-03-nobody-understands-rest-or-http) + +Steve vysvětluje, že spousta problémů, které vývojáři řeší, už jsou v HTTP dávno vyřešeny a stačí je použít - psát API, která s HTTP nebojují, ale využívají jej jako stavební kámen. Část tohoto známého článku se zabývá také verzováním. + +### [Scott Seely: Versioning REST Services](http://www.informit.com/articles/article.aspx?p=1566460) + +Pěkné shrnutí uvedených dvou používaných možností - prefixu v URL a typů v hlavičkách.