V minulém článku jsem mluvil o celkovém pohledu na API, jeho správu a vývoj. Dnes už si vyzkoušíme první jednoduchá API a tranformace.
V dnešní ukázce budu používat čtyři odlišné backend systémy. Budou jinak implementované a některé i ne zrovna korektní (například si nebudou lámat hlavu s hlavičkami).
První backend API bude simulované řešení, které bude na základě dotazu na jméno dávat dodatečné informace o osobě. Řešení postavím na Azure Function (serverless) ve formě HTTP trigger a s navrácenou odpovědí.
Budu používat GET a očekávam parametr v URL se jménem "name". Kód bude jen staticky vracet hodnotu pro osobu Tomas, pro ostatní řetězce oznámí, že záznam nebyl nalezen a vrátí kód 404. Pokud bude v dotazu chybět klíč name, vrátíme chybu 400.
module.exports = function (context, req) { if (req.query.name) { if (req.query.name == "Tomas") { context.res = { body: {"person": {'name': 'Tomas', 'Employer': 'Microsoft'}} } } else { context.res = { status: 404, body: 'Person not found' } }; } else { context.res = { status: 400, body: 'Please pass a name in the request body as {"name": "RequestedName"}' }; } context.done(); };
Funkčnost API si otestuji přímo z GUI.
Přístup ke službě je na základě znalosti přístupového kódu. Ten zjistíme jednoduše:
Tím máme zjištěnou i URL. Pojdmě na další backend.
V druhé funkci uděláme něco podobného (budeme vracet zboží na skladě), ale záměrně jinak. Opět použijeme GET a to na co se ptáme budeme dávat přímo do URL cesty. To v Azure Function uděláme jako routing template:
Kód bude nějak takhle:
module.exports = function (context, req) { var product = context.bindingData.product; if (product) { xml ='<?xml version="1.0" encoding="UTF-8" ?><root><product>%</product><stock>38</stock></root>' xmlres = xml.replace('%', product); context.res = { body: xmlres }; } else { context.res = { status: 400, body: "Please pass a product within URL: /stock/{product}" }; } context.done(); };
Můžeme si otestovat.
A na závěr si opět vezmeme URL a bezpečnostní kód.
Představme si, že do našehu systému zadáváme dlouhodobé úlohy zapsáním do fronty jako je Azure Storage Queue nenbo Azure Service Bus. Pokud tohle budeme chtít zpřístupnit bude asi vhodné napsat mikroslužbu, která poslouchá na REST a založí zprávu ve frontě (z té si třeba další systém může část AMQP prokolem v případě Service Bus). To samé ale můžeme vyřešit rovnou v rámci API managementu, tedy publikovat fasádní API pro příjem zprávy a to poslat na frontu (podporuje totiž HTTP protokol). Proč uvádím takový příklad? Jde o to, že budeme mít zase jiný způsob autentizace backendu a také budeme potřebovat machinace s hlavičkami.
Vytvořte si Azure Service bus a založte v něm frontu.
Poznamenejte si klíče, vrátíme se k nim později.
Stavět klasický SOAP se mi nechtělo, tak využijme některou z veřejně dostupných služeb. Použiji SOAP službu pro geolokaci IP adresy (http://www.webservicex.net/New/Home/ServiceDetail/64). Poznamejme si její definici, tedy http://www.webservicex.net/geoipservice.asmx?WSDL
API můžeme importovat ze Swaggeru a v případě Azure Function bychom také mohli jít rovnou. Ze studijních důvodů to ale teď uděláme ručně.
Založíme naše pardání API a rovnou ho zařadíme do předpripraveného produktu Unlimited (o balíčkování API nabídek jindy).
Pro naše první backend API si přidáme první operaci.
Náš backend reaguje na /person, ale to je z historických důvodů (nebyl to dobrý nápad), pro fasádu bych tomu raději říkal /user.
Na jednotlivých záložkách budeme definovat jak vypadá dotaz, jaké mají být hlavičky, jaké odpovědi budeme dávat apod. To slouží především z důvodu automatického generování dokumentace pro developerský web a také generování WADL či openAPI specifikací, které tam vzniknout ke stažení. Můžeme tedy popsat co požadujeme v body jako vstup a dát příklad.
Pojďme zdokumentovat naši odpověď. Nejprve nadefinujeme odpověď 200.
Přidáme 404 a 400.
Uložíme a tímto máme nadefinovanou fasádu. Z přehledného GUI je dobře vidět, že teď můžeme přidat vstupní politiky (machinace s hlavičkou, přidávání a odebírání atributů, rate limit apod.), nastavit backend volání a v opačném směru přidat výstupní politiku (například převod z XML do JSON).
Při volání backendu je tento zabezpečen kódem, který nám Function vygenerovala. Pokud se podíváte na URL tak vypadá nějak takhle: https://tomasfunction.azurewebsites.net/api/person?code=KkZxxxxxxxwqg==
Potřebujeme tedy provést dvě věci. Naše fasáda má operaci na /user, zatímco backend na /person. Druhá věc je, že potřebujeme přidat parametr code se správnou hodnotou (uživatel fasády samozřejmě nemusí a vlastně ani nesmí vědět jak a kam se dostáváme na backendu). Klikněte na tuštičku u Inbound procession a nastavíme si to.
Uložíme. Poslední, co potřebujeme v tomto API ještě udělat, je definovat správný backend. Zadáme tam tedy hlavní URL naší Azure Function.
V mém případě to bude https://tomasfunction.azurewebsites.net/api/
Já myslím, že máme hotovo můžeme si vyzkoušet. K přístupu k fasádnímu API je samozřejmě potřeba být zaregistrovaný a získat kód pro používání. GUI nám ale umožní rovnou použít kód administrátora.
Všimněte si hlaviček - v příštích dílech nás budou docela zajímat.
Vyplnil se nám to rovnou ten příklad, co jsme zadávali při definici API, ale můžete ho klidně změnit.
Funguje!
Podívejte se na trace. Protože jsme administrátoři a flag jsme zapnuli v hlavičce máme pro účely ladění možnost vidět kompletní trace - jak systém přijímá, modifikuje zprávy, přepisuje URL, kontaktuje backend, co ten vrací a tak dále.
Poslední věc - celé politiky může dělat v GUI, ale stejnak pokročilejší věci tam dostaneme jen v textovém konfiguračním formátu. Podívejte se na jeho obsah tak, jak to odpovídá naklikání v GUI.
Takhle to vypadá - jedná se o XML a na pravé straně máte konfigurační snipplety.
Podívejme se ještě také jak tohle API vypadá v developerském portálu.
Detaily jak pracovat s developerským portálem probereme jindy.
Druhý backend bohužel pro nás funguje jinak a určitě chceme chování sjednotit tak, aby bylo na fasádě stejné, jako to pro /user. Vytvořte si API postupem, který už známe - zaměříme se jen na rozdíly. Musíme vyřešit dvě věci. Jednak fasáda bude specifikovat produkt v rámci query, ale naše backend služba používá produkt v rámci URL. Druhá věc k řešení je to, že backend vrací XML, ale my chceme ve fasádě dávat JSON. Takhle vypadá výsledná politika graficky:
Nejprve tedz vyřešíme zadání dotazu v query a konverzi na URL cestu. V inbound processing tedy kromě přidání code atributu jako minule specifikujeme rewrite URI na z /stock na / (důvodem je, že si pohrajeme s nastavení backend URL, takže nic nepotřebujeme přidávat nebo jinak přepisovat). To daleko důležitější je nastavení našeho backendu:
Použijeme tohle místo URL:
@("https://tomasfunction.azurewebsites.net/api/stock/" + context.Request.Url.Query.GetValueOrDefault("product"))
Co to je? Je to C# kód, byť jen jeho velmi jednoduché použití. V rámci vašich politik můžete použít i daleko složitější manipulace, které zapíšete ve formě kódu. V mém případě jde jen o to, že vezmu začátek URL jako řetězec a přidám k němu hodnotu řetězce, který je v GET dotazu jako hodnota klíče product. Tímto jednoduchým způsobem jsem konvertovat query na URL cestu.
Druhým úkolem je konverze XML na JSON. K tomu budeme definovat outbound politiku a tato nemá přímo reprezentaci v grafickém prostředí. Otevřeme si tedy kódový editor a můžeme použít snipplety na pravé straně (nebo psát přímo co potřebujeme). Výsledný kód všech politik vypadá takhle:
<policies> <inbound> <base /> <set-query-parameter name="code" exists-action="override"> <value>kE0XPBBBU9zDzWjKj2sO1UFnLC3qgnXah04d6jkzxMhkEGIvUWIdFg==</value> </set-query-parameter> <set-backend-service id="apim-generated-policy" base-url="@("https://tomasfunction.azurewebsites.net/api/stock/" + context.Request.Url.Query.GetValueOrDefault("product"))" /> <rewrite-uri id="apim-generated-policy" template="/" /> </inbound> <backend> <base /> </backend> <outbound> <xml-to-json kind="direct" apply="always" consider-accept-header="false" /> <base /> </outbound> <on-error> <base /> </on-error> </policies>
Není to složité, že? Pojďme otestovat.
Už jsme si vytvořili Azure Service Bus. Do něj lze přistupovat jednak AMQP protokolem, ale také přes HTTP. Pochopitelně to vyžaduje nějakou autentizaci (konkrétně přes SAS), kterou nechceme zpřístupnit ven. Pojďme tedy vytvořit fasádu, která nám umožní vytvořit task ve frontě, aniž by tyto podrobnosti musel vývojář znát.
Nejprve potřebujeme vygenerovat SAS token - to se vytváří z klíčů, které najdete v GUI Service Bus. Token si můžete spočítat sami nebo použijte třeba tento nástroj: https://danvy.tv/sas-token-generator.html
Abych mohl sledovat zprávy v Service Bus aniž bych musel psát kód, stáhnul jsem si Azure Service Bus explorer: https://github.com/paolosalvatori/ServiceBusExplorer
Potřebujeme tedy především do hlaviček přidat potřebné autorizační informace. Výsledná politiky vypadá takhle:
Bohužel musel jsem zadávat výhradně v kódu, protože autentizační token obsahuje znak &, který se enginu na tvorbu politik nelíbí - musíme ho překonvertovat na URL bezpečný & To ale při načtení do GUI systém interpretuje a amp; odstraní, takže v tomto specifickém případě musíme zůstat na úrovni kódového zobrazení. To vypadá takhle:
<policies> <inbound> <base /> <set-backend-service id="apim-generated-policy" base-url="https://tomasbus.servicebus.windows.net/myqueue/" /> <rewrite-uri id="apim-generated-policy" template="/messages" /> <set-header name="Authorization" exists-action="override"> <value>SharedAccessSignature sig=HyZDBEYfXXXXXXXXXXN8BhJuYfLyJulnF7QTok%2f6hA%3d&se=1543576641&skn=RootManageSharedAccessKey&sr=https%3a%2f%2ftomasbus.servicebus.windows.net%2fmyqueue</value> </set-header> <set-header name="Content-Type" exists-action="override"> <value>application/atom+xml;type=entry;charset=utf-8</value> </set-header> <set-header name="BrokerProperties" exists-action="override"> <value>{}</value> </set-header> </inbound> <backend> <base /> </backend> <outbound> <base /> </outbound> <on-error> <base /> </on-error> </policies>
Vyzkoušejme.
V Service Bus Exploreru vidím svoje zprávy úspěšně založené!
Na závěr dnešní ukázky si zkusíme vystavět REST fasádu k nějakému staršímu SOAP API. Jak už víme použijeme SOAP v Internetu pro geolokaci IP adresy jehož schéma je zde: http://www.webservicex.net/geoipservice.asmx?WSDL
Přidejme nové API z WDSL.
Nasměrujeme na jeho definici, vybereme Interface, pojmenujeme.
To je všechno! Azure API Management pro nás potřebnou REST fasádu vygeneroval.
Přidejte toto API do výchozího produktu Unlimited a vyzkoušíme.
Dnes jsme si ukázali vytvoření fasády pro různé formy backendového API a použili jsme i nějaké "středně složité" tranformace jako je query na URL, XML na JSON, nebo ze SOAP do REST. API Management toho ale umí daleko víc - někdy příště se podíváme na caching, verzování a mocking, importy a exporty API, produkty a kvóty, pokročilé zabezpečení či úprava developerského portálu. Vracejte se pro další. Azure API Management je skutečně mocný nástroj ať už váš backend běží v cloudu nebo u vás. API je dnes klíčem k inovacím i novým obchodním vztahům a jeho správa je hodně důležitá. Vyzkoušejte si to v Azure.