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.
Varování
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:
(venv)$ pip install requests
Pokud jste prošli 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 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:
import requests
response = requests.get("https://cojeapi.honzajavorek.now.sh/")
print(response.status_code)
print(response.headers)
print(response.text)
Napsali jsme program, který je ekvivalentem následujícího příkazu:
$ curl "https://cojeapi.honzajavorek.now.sh/"
Zkusme jej spustit, zatímco nám ve vedlejším okně jede naše API:
$ python client.py
200
{'Date': 'Sat, 04 May 2019 12:10:32 GMT', 'Content-Type': 'application/json', 'Connection': 'keep-alive', 'content-length': '129', 'cache-control': 'public, max-age=0, must-revalidate', 'x-now-cache': 'MISS', 'x-now-trace': 'zrh1', 'server': 'now', 'x-now-id': 'xdnnz-1556971832381-676f32a6396e2c1aff6d1100d3a5fd54', 'strict-transport-security': 'max-age=63072000'}
{"name": "Honza", "surname": "Javorek", "socks_size": "42", "movies_watchlist_url": "https://cojeapi.honzajavorek.now.sh/movies"}
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:
import requests
response = requests.get("https://cojeapi.honzajavorek.now.sh/")
print(response.status_code)
print(response.headers)
print(response.text['surname'])
$ python client.py
200
{'Date': 'Sat, 04 May 2019 12:19:48 GMT', 'Content-Type': 'application/json', 'Connection': 'keep-alive', 'content-length': '129', 'cache-control': 'public, max-age=0, must-revalidate', 'x-now-cache': 'MISS', 'x-now-trace': 'zrh1', 'server': 'now', 'x-now-id': 'mmxqr-1556972388219-44d1b59d32681aa7074f73fcc1182fbd', 'strict-transport-security': 'max-age=63072000'}
Traceback (most recent call last):
File "client.py", line 7, in <module>
print(response.text['surname'])
TypeError: string indices must be integers
Tělo je text ve formátu JSON (což nám sděluje i hlavička Content-Type). Nešlo by jej nějak dostat jako slovník? Šlo - přesně na toto mají Requests metodu .json():
import requests
response = requests.get("https://cojeapi.honzajavorek.now.sh/")
print(response.status_code)
print(response.headers)
print(response.json())
Nyní máme z textu ve formátu JSON obyčejný Python slovník:
$ python client.py
200
{'Date': 'Sat, 04 May 2019 12:15:59 GMT', 'Content-Type': 'application/json', 'Connection': 'keep-alive', 'content-length': '129', 'cache-control': 'public, max-age=0, must-revalidate', 'x-now-cache': 'MISS', 'x-now-trace': 'zrh1', 'server': 'now', 'x-now-id': 'xdnnz-1556972159138-9eb3b82b14895f7f03b76b8c336b6ca1', 'strict-transport-security': 'max-age=63072000'}
{'name': 'Honza', 'surname': 'Javorek', 'socks_size': '42', 'movies_watchlist_url': 'https://cojeapi.honzajavorek.now.sh/movies'}
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.
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.
import requests
response = requests.get("https://cojeapi.honzajavorek.now.sh/movies")
movies = response.json()
for movie in movies:
print(movie['name'])
Pokud program spustíme, měl by vypsat všechny filmy z dotazovaného API:
$ python client.py
The Last Boy Scout
Mies vailla menneisyyttä
Sharknado
Mega Shark vs. Giant Octopus
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.
import requests
response = requests.get("https://cojeapi.honzajavorek.now.sh/movies")
movies = response.json()
for movie in movies:
response = requests.get(movie['url'])
movie_details = response.json()
print(movie_details['name'], movie_details['year'])
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čí.
$ python client.py
The Last Boy Scout 1991
Mies vailla menneisyyttä 2002
Sharknado 2013
Mega Shark vs. Giant Octopus 2009
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 Návrh API 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ší.
import requests
response = requests.get("https://cojeapi.honzajavorek.now.sh/movies")
movies = response.json()
newest_movie = None
for movie in movies:
response = requests.get(movie['url'])
movie_details = response.json()
if newest_movie is None:
newest_movie = movie_details
elif newest_movie['year'] < movie_details['year']:
newest_movie = movie_details
print('Nejnovější film:', newest_movie['name'], newest_movie['year'])
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.
$ python client.py
Nejnovější film: Sharknado 2013
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¶
Varování
Tato kapitola není ještě připravena.
Zapisujeme¶
Varování
Tato kapitola není ještě připravena.
Mažeme¶
Varování
Tato kapitola není ještě připravena.
Kódování parametrů¶
Varování
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í¶
Varování
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
Specializované knihovny (SDK)¶
Varování
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