{"cells": [{"cell_type": "markdown", "id": "1", "metadata": {}, "source": ["\n", "\n", "## ![](https://s3.amazonaws.com/python-ga/images/GA_Cog_Medium_White_RGB.png) {.separator}\n", "\n", "

Introduction to APIs

\n", "\n", "\n", "\n", "\n", "---\n", "\n", "## Lesson Objectives\n", "\n", "*After this lesson, you will be able to\u2026*\n", "\n", "- Describe what an application programming interface (API) is and why we might use one.\n", "- Identify common APIs on the web.\n", "- Call an API.\n", "\n", "---\n", "\n", "## Discussion: Web Magic\n", "\n", "Have you seen\u2026\n", "\n", "- A website with Google Maps on the page (like Yelp)?\n", "- A program that had live stock market info?\n", "- A website that isn't Twitter but shows a live Twitter feed?\n", "- Any app that pulls info from somewhere else?\n", "\n", "How did they do this?\n", "\n", "![](https://twimgs.com/ddj/images/article/2014/0314/GoogleMap_adrian.gif)\n", "\n", "\n", "\n", "\n", "---\n", "\n", "## APIs (Application Program Interfaces)\n", "\n", "An API is a service that provides raw data for public use.\n", "\n", "APIs give us data, maps, anything!\n", "\n", "| What's the API? | Sample URL \u2014 put this in a new tab! |\n", "|------|------------|\n", "| **The Star Wars API: Request R2-D2 info** | http://swapi.co/api/people/3 |\n", "| **Markit Digital's API: Request current Apple stock info** | http://dev.markitondemand.com/Api/Quote/xml?symbol=AAPL |\n", "| **OpenWeatherMap: The current weather in London** | https://samples.openweathermap.org/data/2.5/weather?q=London,uk&appid=b6907d289e10d714a6e88b30761fae22 |\n", "\n", "Do you think you've been on websites that call an API?\n", "\n", "> Does the JSON look unreadable in the browser? If you're using Chrome, install the [JSONView plugin](https://chrome.google.com/webstore/detail/jsonview/chklaanhfefbnpoihckbnefhakgolnmc?hl=en).\n", "\n", "\n", "\n", "\n", "---\n", "\n", "## How Do We Use an API?\n", "\n", "We'll use the `requests` module.\n", "\n"]}, {"cell_type": "code", "id": "2", "metadata": {}, "outputs": [], "source": []}, {"cell_type": "markdown", "id": "3", "metadata": {}, "source": ["\n", "This works, but there's one very helpful line missing!\n", "\n", "Before we see this in action, let's look at what the API might return.\n", "\n", "\n", "\n", "---\n", "\n", "## JSON vs. XML\n", "\n", "\n", "Imagine: You write code for a list.\n", "\n"]}, {"cell_type": "code", "id": "4", "metadata": {}, "outputs": [], "source": []}, {"cell_type": "markdown", "id": "5", "metadata": {}, "source": ["\n", "But then, `my_list` is unexpectedly a dictionary, or an int, or even a class! The code we wrote won't work.\n", "\n", "APIs can give data back in two ways: JSON or XML. Depending on what the API does, we need to write our program a different way.\n", "\n", "\n", "\n", "\n", "---\n", "\n", "## How Do APIs Give Us Info? Option 1: JSON\n", "\n", "\n", "Here's a potential return from an API:\n", "\n"]}, {"cell_type": "code", "id": "6", "metadata": {}, "outputs": [], "source": []}, {"cell_type": "markdown", "id": "7", "metadata": {}, "source": ["\n", "Looks like a dictionary with a list of dictionaries inside it, right?\n", "\n", "But it's not a dictionary! It's **JSON** (JavaScript Object Notation).\n", "\n", "The `requests` module has a [built-in JSON decoder](http://docs.python-requests.org/en/master/user/quickstart/#json-response-content) to turn JSON into a Python dictionary.\n", "\n", "We can **decode** JSON with `decoded_data = response_from_request.json()`.\n", "\n", "\n", "\n", "\n", "---\n", "\n", "## How Do APIs Give Us Info? Option 2: XML\n", "\n", "Instead of JSON, we might get XML:\n", "\n"]}, {"cell_type": "code", "id": "8", "metadata": {}, "outputs": [], "source": []}, {"cell_type": "markdown", "id": "9", "metadata": {}, "source": ["\n", "JSON is certainly easier to read!\n", "\n", "- We'll stick with JSON whenever we can.\n", "\n", "> **Pro tip:** Most of you don't need to know about XML, but if you're working with legacy code or an older API, you may have to use it. In that case, look up [Element Tree XML](https://python.readthedocs.io/en/stable/library/xml.etree.elementtree.html).\n", "\n", "\n", "\n", "\n", "---\n", "\n", "## Let's Choose an API\n", "\n", "**To recap:** APIs give us data we can use in either XML or JSON.\n", "\n", "Let's call one!\n", "\n", "Check out http://api.open-notify.org/astros.json, which tells us the people currently aboard the International Space Station (ISS).\n", "\n"]}, {"cell_type": "code", "id": "10", "metadata": {}, "outputs": [], "source": []}, {"cell_type": "markdown", "id": "11", "metadata": {}, "source": ["\n", "\n", "\n", "\n", "\n", "---\n", "\n", "## Calling an API\n", "\n", "- Import the `request` module.\n", "- Call the API (`requests.get()`).\n", "- Parse the response with `response.json()`.\n", "\n", "\n", "\n", "\n", "\n", "\n", "---\n", "\n", "## You Do: Calling an API\n", "\n", "Open a new file, `my_api.py`. Type and run the code:\n", "\n"]}, {"cell_type": "code", "id": "14", "metadata": {}, "outputs": [], "source": []}, {"cell_type": "markdown", "id": "15", "metadata": {}, "source": ["\n", "\n", "\n", "\n", "---\n", "\n", "## We Do: A New API\n", "\n", "Awesome! Go back to your file. Let's instead call this URL:\n", "\n", "`http://dev.markitondemand.com/Api/Quote/xml?symbol=AAPL`\n", "\n", "Why does it break? We can't parse XML like JSON.\n", "\n"]}, {"cell_type": "code", "id": "16", "metadata": {}, "outputs": [], "source": []}, {"cell_type": "markdown", "id": "17", "metadata": {}, "source": ["\n", "\n", "\n", "\n", "---\n", "\n", "## Quick Review\n", "\n", "We've called an API! Great job. We did this with the `get()` function in the `requests` module. APIs are made available by other websites or applications. They give us data we can use in either XML or JSON.\n", "\n"]}, {"cell_type": "code", "id": "18", "metadata": {}, "outputs": [], "source": []}, {"cell_type": "markdown", "id": "19", "metadata": {}, "source": ["\n", "\n", "JSON:\n", "\n"]}, {"cell_type": "code", "id": "20", "metadata": {}, "outputs": [], "source": []}, {"cell_type": "markdown", "id": "21", "metadata": {}, "source": ["\n", "---\n", "\n", "## Quick Review\n", "\n", "XML:\n", "\n"]}, {"cell_type": "code", "id": "22", "metadata": {}, "outputs": [], "source": []}, {"cell_type": "markdown", "id": "23", "metadata": {}, "source": ["\n", "\n", "---\n", "\n", "## You Do: Back to JSON\n", "\n", "Back in your file, change the API call back to `http://api.open-notify.org/astros.json`.\n", "\n", "Once it's decoded, it's a dictionary!\n", "\n", "Replace your `print` statement:\n", "\n"]}, {"cell_type": "code", "id": "24", "metadata": {}, "outputs": [], "source": []}, {"cell_type": "markdown", "id": "25", "metadata": {}, "source": ["\n", "Can we go further? Try to only print the `name`s of the astronauts.\n", "\n", "\n", "\n", "\n", "---\n", "\n", "## Name Printing: Solution\n", "\n", "Working backward, we have a:\n", "\n", "- Dictionary (key: `name`).\n", "- Which is inside a list (the value of `people`).\n", "- Which is inside a dictionary (key: `people`).\n", "\n"]}, {"cell_type": "code", "id": "26", "metadata": {}, "outputs": [], "source": []}, {"cell_type": "markdown", "id": "27", "metadata": {}, "source": ["\n"]}, {"cell_type": "code", "id": "28", "metadata": {}, "outputs": [], "source": []}, {"cell_type": "markdown", "id": "29", "metadata": {}, "source": ["\n", "\n", "\n", "\n", "\n", "---\n", "\n", "## You Do: Shakespeare\n", "\n", "In your file, call the Shakespeare API `http://ShakeItSpeare.com/api/poem`.\n", "\n", "Print only the poem.\n", "\n", "\n", "\n", "\n", "---\n", "\n", "## Shakespeare: Solution\n", "\n", "Print only the poem.\n", "\n"]}, {"cell_type": "code", "id": "30", "metadata": {}, "outputs": [], "source": []}, {"cell_type": "markdown", "id": "31", "metadata": {}, "source": ["\n", "\n", "\n", "\n", "---\n", "\n", "## Quick Review\n", "\n", "When we convert JSON, it keeps the same format, only in a Python structure.\n", "\n", "When parsing an API's return, look through the JSON to find the exact structure you need. Is it the string value from the `poem` key? Or the value from each `name` key in a list of dictionaries, which is the value of the `people` key?\n", "\n", "Think it through before writing your code.\n", "\n"]}, {"cell_type": "code", "id": "32", "metadata": {}, "outputs": [], "source": []}, {"cell_type": "markdown", "id": "33", "metadata": {}, "source": ["\n", "\n", "\n", "\n", "---\n", "\n", "## I Do: API Authentication\n", "\n", "\n", "Many APIs are free but require a **key**. This identifies the developer requesting access.\n", "\n", "If we call the Giphy API:\n", "\n", "- With no key, `http://api.giphy.com/v1/gifs/search?q=funny+cat`, we get `Error - Unauthorized`!\n", "\n", "- With a key, `http://api.giphy.com/v1/gifs/search?q=funny+cat&api_key=dc6zaTOxFJmzC`, it works!\n", "\n", "---\n", "\n", "## I Do: API Authentication\n", "\n", "Syntax Notes:\n", "\n", "- The main API URL is `http://api.giphy.com/v1/gifs/search`.\n", "- `?` always delineates a URL and its parameters.\n", " - (The `?` is a standard for every URL! Searching Google for \"banana,\" with `q` short for \"query:\" `https://www.google.com/search?q=banana`).\n", " - (Here's another one! Searching Amazon for \"banana:\" `https://www.amazon.com/s?field-keywords=banana`.)\n", "\n", "**Most importantly**, never publish your key for a backend service, including on GitHub! (This is an example.) There are other ways to provide your key to a server in order to keep that key safe. However, if your code is using JavaScript, that's ok as that provides only read access in general (assuming you have your permissions properly configured.) This is a sticking point for developers coming to Python from a front-end perspective.\n", "\n", "\n", "\n", "---\n", "\n", "\n", "## You Do: JSONPlaceholder API\n", "\n", "Read about the API here.\n", "\n", "Call this URL: https://jsonplaceholder.typicode.com/users/1 .\n", "\n", "- Display the name, username, email and phone that came back from the API.\n", "\n", "\n", "\n", "---\n", "\n", "## JSONPlaceholder API Solution\n", "\n", "\n", "---\n", "\n", "## Summary\n", "\n", "APIs:\n", "\n", "- Handy URLs from which we can get information.\n", "- Sometimes require keys.\n", "- Usually free.\n", "- Call with the `requests()` module.\n", "\n", "XML and JSON:\n", "\n", "- Two formats in which APIs might return information to us.\n", "- XML is legacy.\n", "- JSON looks like a dictionary.\n", "\n", "---\n", "\n", "\n", "## Additional Resources\n", "\n", "- Here's an example of a [stolen key horror story](https://wptavern.com/ryan-hellyers-aws-nightmare-leaked-access-keys-result-in-a-6000-bill-overnight).\n", "- The [Programmable Web API Directory](http://www.programmableweb.com/apis/directory)\n", "- [Element Tree XML](https://python.readthedocs.io/en/stable/library/xml.etree.elementtree.html)\n"]}], "metadata": {"kernelspec": {"display_name": "Python 3", "language": "python", "name": "python3"}, "language_info": {"codemirror_mode": {"name": "ipython", "version": 3}, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.6"}}, "nbformat": 4, "nbformat_minor": 5}