Změny API

Changelogy webhooků: breaking change, o kterou nikdo nežádal

5 min čtení

Changelog REST API existuje proto, že volající si může vybrat odmítnout odpověď, které nerozumí, nebo aspoň zalogovat chybu dost hlasitě, aby si toho někdo všiml. Příjemce webhooku zřídka dělá jedno nebo druhé. Dostane POST, přečte pole, která očekává, a pokud se pole přesunulo, změnilo typ nebo zmizelo, endpoint buď potichu spadne uvnitř background jobu, který nikdo nesleduje, nebo, hůř, běží dál se špatnou hodnotou, kterou nikdy nevalidoval. Co je breaking change pokrývá obecnou definici; payload webhooku potřebuje vlastní odpověď, protože způsob selhání je jiný než u endpointu, který někdo volá záměrně.

Proč se změna payloadu webhooku rozbíjí jinak než změna odpovědi API?

Protože směr požadavku je obrácený. Volající REST iniciuje volání a může přidat hlavičku verze, zopakovat pokus při 4xx nebo přečíst upozornění o vyřazení v odpovědi. Příjemce webhooku nic z toho neiniciuje: váš server rozhodl odeslat, rozhodl kdy, a rozhodl, jaký tvar bude mít tělo. Jedinou pákou příjemce je validace, kterou napsal, když se integrace stavěla, a většina integrací se postaví jednou, fungují, a nikdo se k nim znovu nevrací, dokud se nerozbijí. Tato asymetrie je celý důvod, proč změna payloadu webhooku zaslouží víc opatrnosti než stejná změna v těle odpovědi, kterou si volající aktivně vyžádal.

Co se opravdu počítá jako breaking change v payloadu webhooku?

ZměnaBreaking pro většinu příjemců
Přidání nového poleNe, pokud příjemci ignorují neznámá pole (tento předpoklad ověřte, nepředpokládejte)
Odebrání poleAno, pokud ho něco čte
Přejmenování poleAno, funkčně totožné s odebráním starého
Změna typu pole (string na objekt)Ano, téměř vždy
Přeuspořádání polí v JSON těleNe, pro jakéhokoli příjemce parsujícího podle klíče, což by měli být všichni
Změna názvu nebo typu událostiAno, pokud podle toho příjemci filtrují nebo routují

Řádek “přidání pole je bezpečné” je ten, na který se týmy spoléhají nejvíc a nejvíc se vyplatí ho ověřit, ne předpokládat. Permisivní JSON parser ve výchozím stavu ignoruje neznámá pole, ale příjemce, který deserializuje do přísného schématu, několik typovaných jazyků to dělá bez další konfigurace, může odmítnout celý payload, jakmile se objeví neočekávané pole. Přidání pole je pro váš webhook bezpečné jen tehdy, když víte, jak příjemci parsují, ne protože je JSON sám o sobě permisivní.

Jak verzovat payload webhooku?

Podobně jako u odpovědi API, s jedním rozdílem: příjemce nikdy neposílá požadavek, takže si o verzi nemůže říct, a odesílatel ji musí uvést. Může jít do těla nebo do hlavičky požadavku samotného doručení; doručení GitHubu nesou X-GitHub-Event a X-GitHub-Hook-ID, a specifikace Standard Webhooks dává svá metadata do hlaviček webhook-*. Pole verze v payloadu ("payload_version": 2) je nejlevnější možnost a funguje, když jsou příjemci ochotni podle něj větvit. Verzovaný typ události (invoice.updated se stane invoice.updated.v2 jako samostatná událost, ke které se příjemce dobrovolně přihlásí) vyžaduje víc práce na postavení, ale znamená, že starý tvar dál proudí těm, kdo nikdy nemigrovali, což tady záleží víc než u REST endpointu, protože nemůžete zavolat každému příjemci, aby aktualizoval. Nastavení na odběr, vybrané při registraci endpointu webhooku, posune rozhodnutí dopředu místo větvení při každém doručení, a je správnou volbou, když už máte záznam odběru, ke kterému ho připojit.

POST /endpoint-prijemce
{
  "event": "invoice.updated",
  "payload_version": 2,
  "data": { "invoice_id": "inv_123", "status": "paid" }
}

Jak vůbec víte, kdo poslouchá?

Hůř než ekvivalentní verze tohoto problému v changelogu API, protože webhook nemá na vaší straně log příchozích požadavků, který by pojmenoval volajícího; máte jen svůj vlastní log odchozích doručení, který říká, že endpoint dostal 200, ne co udělal s tělem. Sledujte minimálně dvě věci: každý registrovaný endpoint s vlastnicí, stejnou disciplínu, jakou changelogy interních API doporučují pro interní konzumenty, a vaši míru neúspěšných doručení na endpoint po změně payloadu. Nárůst odpovědí 4xx nebo 5xx z endpointu hned po změně je nejbližší věc ke stack trace, kterou dostanete, a často jediný signál, že se příjemce rozbil, protože tým, který ho provozuje, si toho nemusí všimnout celé dny.

Měl by být changelog webhooků oddělený od changelogu API?

Oddělená sekce na stejné stránce, ne oddělená publikace. Changelog API už stanovuje, kdo ho čte a jak se odebírá; změna payloadu webhooku patří do stejného feedu, označená dost jasně, aby ji vývojářka na straně příjemce, skenující “ovlivňuje to moji integraci”, mohla vyfiltrovat, protože konzumentka webhooku často nemá jiný důvod kontrolovat obecný changelog API a najde ho jen, když ji tam někdo přímo nasměruje.

Jak by mělo vypadat rozumné okno vyřazení pro payload webhooku?

Delší než ekvivalentní vyřazení REST, protože migrace na straně příjemce obvykle znamená, že druhý tým, se kterým možná nemáte přímé spojení, si toho musí všimnout, naplánovat to a vydat bez vlastní naléhavosti. Měsíc je rozumné minimum pro pole, které příjemce pravděpodobně stále parsuje permisivní knihovnou; tři měsíce nebo víc jsou bezpečnější pro odebrání pole, které by přísné schéma úplně odmítlo. Posílejte starý a nový tvar společně během okna, kdy je to proveditelné (staré pole status a jeho náhrada z verze 2 ve stejném payloadu), protože příjemce, který čte staré pole, funguje dál, aniž by se dotkl svého kódu, a ten, kdo už migroval, prostě ignoruje pole, které už nepotřebuje.

FAQ

Musí konzumenti webhooků potvrdit změnu payloadu před jejím nasazením? Ve výchozím stavu neexistuje potvrzovací mechanismus, a přesně proto tu okno vyřazení záleží víc než u REST API: nikdo nepotvrzuje připravenost, takže okno musí být dost dlouhé, aby většina příjemců migrovala svým vlastním tempem, než starý tvar zmizí.

Je někdy bezpečné přidávat neznámá pole bez upozornění? Jen poté, co jste ověřili, ne předpokládali, že vaši příjemci parsují permisivně. Záznam v changelogu stojí málo a odstraňuje dohady; potichu přidávat pole s předpokladem, že “JSON parsery ignorují navíc”, rozbije jakéhokoli příjemce s přísnou deserializací.

Jaký je nejrychlejší způsob, jak zjistit rozbitého příjemce webhooku po změně payloadu? Míra neúspěšných doručení na endpoint, sledovaná v hodinách hned po změně. Neřekne vám, co se rozbilo, jen že se něco rozbilo, ale je to nejranější a často jediný signál, který dostanete.

Pomáhá logika opakování příjemcům přežít změnu payloadu? Ne. Opakování znovu odešle stejný nový payload; nevrátí se k tvaru, který příjemce dokáže parsovat. Změna payloadu rozbije příjemce při prvním doručení a při každém dalším opakování stejně.


Technická tvrzení v tomto článku nikdo nezávisle neověřil. Pokud tu něco nesedí, dej nám vědět a opravíme to.

Související na changeloop: Dokumentace pro vývojáře, Srovnání nástrojů pro changelog

changeloop
Tým, který vyvíjí changelog uzavírající smyčku. Uživatelé o něco požádají, tvůj tým to doručí, ten, kdo žádal, se to dozví.