APIs and Requests in Flask
Learning Objectives
After this lesson, you will be able to:
- Create an API that makes a
GETrequest with Flask. - Create an API that makes a
POSTrequest with Flask.
Discussion: Remember APIs?
We can call them.
But who publishes them?
Do you think we could make one?
APIs
In your browser, head to https://swapi.co/api/people/13/?format=json.
- That's a collection of data about Chewbacca.
What would it look like in Chewbacca's language?
Head to https://swapi.co/api/people/13/?format=wookiee.
- This is the same data written in Wookiee!
Web API Recap
A list of function calls that are made to remote servers.
- Sent by encoding a URL (an HTTP request).
- We could call the OMDb API to get a movie's information.
Now, we're going to create an API using Flask.
Talking Points:
At a theoretical level, you can think of interfaces kind of analogous to real-world counterparts:
- Door handles. These interfaces get pushed or pulled, and the door opens to a new space. We could even have crazy DeLorean style doors that open upward.
- A standard telephone. When you call someone, you are connected from your space to another space using this interface.
Today, we'll write a function based on displaying a list of heroes of the Python/programming world.
Using the abstracted examples from a second ago, you can think of the function call as the phone number that you're dialing, or the handle that you make a request on.
Many web programmers today use web APIs. The rise of JavaScript and the current state of programming techniques are the principal movers of this rise. We're going to create an API today using Flask.
Because of how interactive many websites have become (again, fingers pointed at JavaScript), many other languages like Python started co-opting standards to communicate data to and from servers.
Discussion: The Sides of an API
What's the difference between calling and creating an API?
Talking Point:
- Answer: Calling an API allows you to retrieve data, while creating an API makes some data that you want to publish accessible.
HTTP
- Stands for Hypertext Transfer Protocol.
- A system of rules (protocol) that determines how webpages (hypertext) get sent from one place to another (transfer).
Talking Points:
There are clients that:
- HTTP clients respond to HTTP responses from a web server/HTTP server.
- Web servers receive HTTP requests and generate HTTP responses.
Recap: Clients and Servers
With HTTP, there are two sides:
- Clients
- Make the requests.
- Servers
- Receive those requests.
CRUD
These four functions are everywhere in programming:
- Create
- Read
- Update
- Delete
Talking Points:
- CRUD operations are the four basic functions in persistent storage.
- CRUD operations are everywhere in programming.
- Here, we're most concerned with how our API is going to create, read, and update data via an HTTP URL.
CRUD Mapped to HTTP Requests
What do we do when calling the OMDb API?
GET:- Read.
- "Tell me all values in
instrument_list."
POST:- Usually Create, sometimes Update.
- "Add
cellotoinstrument_list."
PUT:- Similar to
POST. - Create or Update an entity.
- Similar to
PATCH:- Update only a specified field.
- "In
instrument_list, changeguitar_typetobass."
DELETE:- Delete!
- "Delete
instrument_list." - Doesn't necessarily happen immediately.
Talking Points:
- Here are HTTP methods used to map to CRUD (create, read, update, delete) operations to HTTP requests:
GET,PUT, andPATCH.
- They must be safe and idempotent (i.e., regardless of how many times it repeats with the same parameters, the results are the same).
Knowledge Check
What does CRUD stand for?
Talking Point:
- Answer: "Create, Read/Retrieve, Update, and Delete/Destroy."
Knowledge Check: POST and GET
What's the difference between a POST and GET request?
Talking Point:
- Answer: A
POSTrequest will create or update something, while aGETrequest will read something.
Creating an API With Flask
We're going to create an example of an API that:
- Takes in a list of dictionaries.
- Parses that list based on what we pass into the API.
- Returns a JSON with the appropriate data.
Remember JSON?
- Both dictionaries and JSONs have key-value pairs.
- Both dictionaries and JSONs are wrapped in curly brackets (
{}).
heroes_dictionary = {'person': 'Peter_Norvig', 'person': 'Gilbert_Strang', 'person': 'Ada_Lovelace', 'person': 'Guido_van_Rossum'}
heroes_json = [{'person': 'Peter_Norvig'}, {'person': 'Gilbert_Strang'}, {'person': 'Ada_Lovelace'}, {'person': 'Guido_van_Rossum'}]
Talking Points:
- The most that we need to know right now about JSON is that it has a similar data structure in Python: the dictionary.
- We're going to modify
hello_api.pyagain in your code editor.
We Do: Basic App
- Create a new Flask app,
hello_api.py.
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return "Hello, World"
if __name__ == '__main__':
app.run(debug=True)
Check that it works!
We Do: New Functions
- Import two new functions:
jsonifyandrequest.
from flask import Flask, jsonify, request
Talking Point:
- Explain why we're taking these in.
We Do: First API Route
- Add a new route under our
hellohome page.
@app.route('/api', methods=['GET'])
def returnJsonTest():
return jsonify({'What happened?': 'It worked!'})
Test both routes:
localhost:5000localhost:5000/api
Talking Points:
- Let's add a new route under our
Hello Worldhome page. - Save your Python file. If we have our code right, our new page should return our JSON!
- Open your browser and first head to
localhost:5000. - Then head to
localhost:5000/api. - It worked! Congratulations!
Knowledge Check: Discussion
What two new functions did we add into our import?
What do they do?
Talking Point:
- Answer:
jsonifyandrequest.
We Do: Altering Data With APIs
Cool!
What if we want the data to change?
Add a list under the
appinstantiation, above the routes.heroes = [{'person': 'Peter_Norvig'}, {'person': 'Gilbert_Strang'}, {'person': 'Ada_Lovelace'}, {'person': 'Guido_van_Rossum'}]
What can we do with that?
Talking Points:
- This is cool, but what if we want that data to change?
- Let's create a list like the one on the screen.
- Let's add that into our script in
hello_api.py.
Teaching Tips:
The code currently is:
from flask import Flask, jsonify, request
app = Flask(__name__)
heroes = [{'person': 'Peter_Norvig'}, {'person': 'Gilbert_Strang'}, {'person': 'Ada_Lovelace'}, {'person': 'Guido_van_Rossum'}]
@app.route('/')
def hello():
return "Hello, World"
@app.route('/api', methods=['GET'])
def returnJsonTest():
return jsonify({'What happened?': 'It worked!'})
if __name__ == '__main__':
app.run(debug=True)
We Do: APIs to Return All Data
- We have a list.
- We need to get data from it.
- Make a new route:
@app.route('/heroes', methods=['GET'])
def gimmeAllHeroes():
return jsonify({'heroes': heroes})
Talking Points:
We also need to add in some code to give us the data from our list.
- We'll add a function to return all the data.
- Type out the code on the slide in your
hello_api.pyscript, below thedef.
There are a few things going on here:
- We loop over our list of heroes.
- We return one of the heroes if our name in the HTTP address matches the name in our function.
We Do: APIs to Return Only SOME Data
- At this route, loop over the heroes.
- Try to find the one we want!
@app.route('/heroes/<string:name>', methods=['GET'])
def gimmeOneHero(name):
names = [hero for hero in heroes if hero['person'] == name]
return jsonify({'hero': names[0]})
Talking Point:
- There are a few things going on here:
- We loop over our list of heroes.
- We return one of the heroes if our name in the HTTP address matches the name in our function.
We Do Aside — Always Error-Check
What happens when you input something that's inaccurate?
This is a good time for error-checking!
def gimmeOneHero(name):
names = [hero for hero in heroes if hero['person'] == name]
if names:
return jsonify({'hero': names[0]})
else:
return "Hero not found"
Create a POST Request With Flask
- What if we want more heroes?
- Let's add data to our list of heroes with a
POSTrequest.POSTwas "Create" (and, very rarely, "Update").
Talking Point:
- Let's try adding data to our list of heroes with a
POSTrequest. Right now, our app looks like the following on the screen.
Adding Our New POST Function
- We can use the same route — with a different method.
@app.route('/heroes', methods=['POST'])
def addMyHero():
newhero = {"person": request.get_json()["person"]}
heroes.append(newhero)
return jsonify({"heroes": heroes})
Talking Points:
- We'll use the same route, and if a
POSTrequest gets made, we'll append that into our heroes list. - Add in the following function that I've named
addMyHero().
Knowledge Check II
Assuming our code doesn't have any errors, what should happen when our POST request takes place?
Talking Point:
- We should append a hero (our data) into our heroes list (our database).
Profit
Now we'll check to see if our POST request works.
Open a new terminal window, and
python hello_api.py.- Launch the app!
Going to
/heroesgives us the heroes list.How do we
POST?We'll use
curl:- A command line tool for getting or sending files with URL syntax.
- Not necessary to memorize!
Talking Points:
- Now we'll check to see if our
POSTrequest works.- Open a new terminal window, and
python hello_api.py.
- Open a new terminal window, and
- This will launch our server.
2. Once your Flask app has started, open a new tab using
Command + T. We need the server to remain running locally. 3. In the new tab, we're going to make aPOSTrequest with a particular content type of JSON. - The content type here is JSON, but we could extend this to be other data types by changing our function and then changing the
cURLcommand we run below. 4. Typecurl -X POST -H "Content-Type: application/json" -d '{"person":"<<insert a name here>>"}' http://localhost:5000/heroes. cURLis a command line tool. It stands for Client URL. Colloquially, we can describe it as being like a browser, but in your command line. More formally, it's a command line tool for getting or sending files with URL syntax. 5. We should see our new hero list with our personal hero appended!
Teaching Tips:
- Walk around while doing this. cURL can be tough. Check for typos!
Trying Out POST and cURL
With the app running, open a new tab in the command prompt.
Replace the name, then copy this right over:
curl -X POST -H "Content-Type: application/json" -d '{"person":"<<INSERT A NAME HERE>>"}' http://localhost:5000/heroes
Check the command line output!
Try going to
http://localhost:5000/heroes— your hero is listed!
Quiz
Which of these is the right code for a POST request?
- Option A
@app.route('/myapiroute', methods=['POST'])
def butAmIMakingARequest():
type_of_request = {"requestType:" :" This is definitely a GET Request"}
requestage.append(type_of_request)
return jsonify({"theAnswer" : requestage})
- Option B
type_of_request = [{"requestType:" :" This is definitely a POST Request"}]
@app.route('/myapiroute', methods=['GET'])
def butAmIMakingARequest():
return jsonify({"theAnswer" : type_of_request})
Talking Point:
- Answer: Despite what the variables and key-value pairs are named, the correct answer is Option A.
Summary
We covered APIs and requests in Flask:
- We made an API using JSON!
- We used
GETto display it. - We used
POSTto add to it.