.. _creating-client: Tvoříme klienta =============== Doteď jsme používali obecného klienta v podobě prohlížeče nebo programu curl. Obecného klienta musí ovládat člověk. To je přesně to, co potřebujeme, když si chceme nějaké API vyzkoušet, ale celý smysl API je v tom, aby je programy mohly využívat automaticky. .. warning:: Na obsahu této části se stále pracuje. Základ aplikace --------------- Pokud chceme naprogramovat klienta pro konkrétní úkol, můžeme ve většině jazyků použít nějakou buďto vestavěnou, nebo doinstalovanou knihovnu. V případě jazyka Python použijeme `Requests `__. Vytvoříme si pro náš projekt nový adresář ``cojeapi-client`` a v něm `virtuální prostředí `__, které si aktivujeme. Poté nainstalujeme Requests: .. code-block:: shell (venv)$ pip install requests Pokud jste prošli :ref:`kapitolou o tvorbě API serveru `, ujistěte se, že pro klienta si vytváříte nový projekt - novou složku, nové virtuální prostředí, atd. Vytváříme novou, na serveru zcela nezávislou a samostatnou aplikaci. Nyní můžeme začít s tvorbou klienta. Jenže specializovaný klient potřebuje nějaké API, na které by se mohl specializovat. K tomu se nám náramně hodí API z předešlé kapitoly. V adresáři ``cojeapi-client`` si vytvoříme nový soubor s názvem ``client.py`` a použijeme v něm Requests pro jednoduchý požadavek na server. Funkce `requests.get `__ nám umožní poslat požadavek metodou :method:`get`. Naše je veřejně dostupné na adrese https://cojeapi.honzajavorek.now.sh, takže ji použijeme jako cíl požadavku. Následně vypíšeme detaily odpovědi, kterou dostaneme: .. literalinclude:: ../code/client/01_base/client.py :language: python Napsali jsme program, který je ekvivalentem následujícího příkazu: .. code-block:: text $ curl "https://cojeapi.honzajavorek.now.sh/" Zkusme jej spustit, zatímco nám ve vedlejším okně jede naše API: .. literalinclude:: ../code/client/01_base/test.txt :language: text A je to, udělali jsme svůj první požadavek na server! Vidíme, že se nám povedlo vypsat status kód odpovědi, hlavičky, i tělo. Hlavičky nám Requests rovnou poskytují jako Python `slovník `__. Tělo odpovědi ale máme zatím jako řetězec. Čteme JSON ---------- Pokud bychom chtěli číst tělo zprávy, narazíme na fakt, že jej máme jako řetězec: .. literalinclude:: ../code/client/02_json_error/client.py :language: python :emphasize-lines: 7 .. literalinclude:: ../code/client/02_json_error/test.txt :language: text :emphasize-lines: 4-7 Tělo je **text ve formátu JSON** (což nám sděluje i hlavička :header:`Content-Type`). Nešlo by jej nějak dostat jako slovník? Šlo - přesně na toto mají Requests metodu `.json() `__: .. literalinclude:: ../code/client/03_json/client.py :language: python :emphasize-lines: 7 Nyní máme z textu ve formátu JSON obyčejný Python slovník: .. literalinclude:: ../code/client/03_json/test.txt :language: text :emphasize-lines: 4 Zpracováváme odpověď -------------------- Program, který dělá totéž co curl, není popravdě moc užitečný program. Pojďme zkusit využít naše API k napsání programu, jenž z něj zjistí seznam filmů a vypíše je. .. tabs:: .. tab:: Cvičení Přepište program tak, aby posílal požadavek na https://cojeapi.honzajavorek.now.sh/movies, přečetl odpověď, prošel všechny filmy získané z těla odpovědi a pomocí ``print()`` vypsal název každého z nich. .. tab:: Řešení .. literalinclude:: ../code/client/04_movies/client.py :language: python Pokud program spustíme, měl by vypsat všechny filmy z dotazovaného API: .. literalinclude:: ../code/client/04_movies/test.txt :language: text .. tabs:: .. tab:: Cvičení Jestliže procházíte tento návod v rámci workshopu, například `PyWorking `__, použijte ve vašem programu místo https://cojeapi.honzajavorek.now.sh adresu API někoho jiného z účastníků. Pokud tam má i jiné filmy než byly v návodu, měl by je program vypsat. Získáváme doplňující data ------------------------- Co kdybychom chtěli ke každému filmu vypsat i rok, kdy byl uveden? Rok není v seznamu filmů k dispozici, nachází se na detailu každého filmu. Budeme tedy muset udělat jeden požadavek na seznam filmů a poté ještě požadavek na každý film ze seznamu, abychom zjistili rok. .. literalinclude:: ../code/client/05_year/client.py :language: python Vidíme, že pro každý film děláme další požadavek na API a teprve z jeho výsledku vypisujeme jméno a rok. Pokud program spustíte, bude trvat podstatně déle, než skončí. .. literalinclude:: ../code/client/05_year/test.txt :language: text To, že musíme posílat požadavek na každý film zvlášť je buď důsledkem toho, že se snažíme z API zjistit kombinaci informací, která není úplně obvyklá, nebo důsledkem toho, že někdo API špatně navrhl. Narazili jsme přesně na tu situaci, která byla popsána v sekci :ref:`apidesign` při tvorbě serveru. Agregované informace -------------------- Data z API nemusíme jen číst a vypisovat. Zajímavější je, když je využijeme ke zjištění nových, dříve netušených informací. Pojďme například zjistit, který z filmů v seznamu je nejnovější. .. literalinclude:: ../code/client/06_newest/client.py :language: python Uvedený kód upravuje předchozí příklad, ale místo vypisování názvů filmů a jejich roků vydání rovnou zjišťuje, který z nich má rok s největší hodnotou. Takový film potom na konci vypíše. .. literalinclude:: ../code/client/06_newest/test.txt :language: text Toto je jen malá ukázka toho, jak lze data z API agregovat, tzn. zjišťovat informace, jejichž výpočet protíná několik odpovědí. Chyby ----- .. warning:: Tato kapitola není ještě připravena. Zapisujeme ---------- .. warning:: Tato kapitola není ještě připravena. Mažeme ------ .. warning:: Tato kapitola není ještě připravena. Kódování parametrů ------------------ .. warning:: Tato kapitola není ještě připravena. .. todo:: co dáváme do parametrů se musí prohnat nějakym urlencoding příklady s nějakým (reverse) geocoding api (google, seznam?) Zabezpečení ----------- .. warning:: Tato kapitola není ještě připravena. .. todo:: mechanismus http/https basic auth oauth většinou nějaký token (vysvětlit token), který se narve do hlavičky auth token - něco vygenerováno jen pro nás, co je tajné a neměli bychom to nikomu dávat a ukazovat příklad s GitHubem, vygenerujeme token, dáme do ENV, nasosáme v programu a můžeme použít Pracujeme s veřejnými API ------------------------- OMDb ^^^^ GitHub ^^^^^^ Specializované knihovny (SDK) ----------------------------- .. warning:: Tato kapitola není ještě připravena. .. todo:: vysvětlit specializovaného klienta příklady .. todo:: připomenout, že než jdeme psát klienta na zelené louce, měli bychom ověřit, že už není nějaká hotová SDK knihovna (příklady z pypi) základní příklady s requests, GET, POST https://github.com/honzajavorek/cojeapi/issues/2