APIs and Requests in Flask
#
Learning ObjectivesAfter this lesson, you will be able to:
- Create an API that makes a
GET
request with Flask. - Create an API that makes a
POST
request with Flask.
#
Discussion: Remember APIs?We can call them.
But who publishes them?
Do you think we could make one?
#
APIsIn 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 RecapA 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 APIWhat'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 ServersWith HTTP, there are two sides:
- Clients
- Make the requests.
- Servers
- Receive those requests.
#
CRUDThese 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 RequestsWhat do we do when calling the OMDb API?
GET
:- Read.
- "Tell me all values in
instrument_list
."
POST
:- Usually Create, sometimes Update.
- "Add
cello
toinstrument_list
."
PUT
:- Similar to
POST
. - Create or Update an entity.
- Similar to
PATCH
:- Update only a specified field.
- "In
instrument_list
, changeguitar_type
tobass
."
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 CheckWhat does CRUD stand for?
Talking Point:
- Answer: "Create, Read/Retrieve, Update, and Delete/Destroy."
POST
and GET
#
Knowledge Check: What's the difference between a POST
and GET
request?
Talking Point:
- Answer: A
POST
request will create or update something, while aGET
request will read something.
#
Creating an API With FlaskWe'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.py
again 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:
jsonify
andrequest
.
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
hello
home page.
@app.route('/api', methods=['GET'])def returnJsonTest(): return jsonify({'What happened?': 'It worked!'})
Test both routes:
localhost:5000
localhost:5000/api
Talking Points:
- Let's add a new route under our
Hello World
home 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: DiscussionWhat two new functions did we add into our import?
What do they do?
Talking Point:
- Answer:
jsonify
andrequest
.
#
We Do: Altering Data With APIsCool!
What if we want the data to change?
Add a list under the
app
instantiation, 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.py
script, 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-CheckWhat 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
POST
request.POST
was "Create" (and, very rarely, "Update").
Talking Point:
- Let's try adding data to our list of heroes with a
POST
request. Right now, our app looks like the following on the screen.
POST
Function#
Adding Our New - 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
POST
request gets made, we'll append that into our heroes list. - Add in the following function that I've named
addMyHero()
.
#
Knowledge CheckAssuming 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).
#
ProfitNow 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
/heroes
gives 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
POST
request 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 aPOST
request 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
cURL
command we run below. 4. Typecurl -X POST -H "Content-Type: application/json" -d '{"person":"<<insert a name here>>"}' http://localhost:5000/heroes
. cURL
is 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!
POST
and cURL
#
Trying Out 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!
#
QuizWhich 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.
#
SummaryWe covered APIs and requests in Flask:
- We made an API using JSON!
- We used
GET
to display it. - We used
POST
to add to it.