Easy-breezy REST API in Python

Making a RESTful API with Python and Flask

A Simple Tutorial Example of a REST API with Flask

Aaron Lee
Level Up Coding
Published in
7 min readJun 16, 2021

--

Photo by Brendan Church on Unsplash

For a recent two day hackathon, I worked with a software developer (Roman Turner) to make a recommendation app. I’m a Data Scientist, so my superpowers are Python, Data Science and Flask. His superpowers are JavaScript and React (amongst others). We decided that he would work on the front-end web app, and I would run a recommendation model on the backend in Python.

To get the two to talk to each other, I built a Flask API which would allow my partner to send JSON requests, and receive a JSON formatted responses from my model.

I have made my share of Flask apps, but mostly independent projects, and I had never made an API. I learned a lot in the process of making one, and want to share some of the process and pitfalls with you.

The purpose of this tutorial is to show you one way to get a working RESTful API using Python and Flask (A RESTful API, just means that the data is handled through HTTP requests). This tutorial assumes intermediate level experience with Python and JSON, and at least some familiarity with the Flask microframework to make web apps. The simple API coded in this tutorial is successfully deployed and hosted on Heroku.com at https://square-flask-api.herokuapp.com/ if you want to make calls directly to it.

The Basic App Setup

I will start by sharing the code and techniques that allowed me to create my first API. The API app below attempts to take in an array of numbers and return their squares.

If you have used Flask before, the above code should look pretty familiar.

Explanation of the code:

  • Line 4: Create the Flask app (goes before the routes).
  • Line 7: Make a single route at the /square/ endpoint of the app. It is set up only for the POST method. POST is for sending data to a server to create/update a resource. In our case, a front-end or outside source is sending data to our API/Flask app.
  • Line 8: The function associated with the /square/ route is called square and is where we will be processing the incoming requests.
  • Line 10: Grab the JSON from the request. If we were sending in the numbers 5, 7 and 15, we could put it in JSON format: [{“number1": 5, “number2":7, “number2”:15}] or something similar.
  • Line 10-11: Grab the data inside the JSON as a python dictionary and extract the values from it. In my case, I’m grabbing the list of numbers (the values from the python dict).
  • Line 13–14: Create a dictionary where we will build our response. We will just put the numbers in a list under the dictionary key ‘results’
  • Line 16–18: Use a loop to go through our list of numbers we extracted from the JSON input. We square the numbers, and append them to the response.
  • Line 20: Use jsonify() from the Flask library to make our output into a JSON friendly format. (this could also be done with the json library)
  • Line 23–24: Start my app.

Test the API Response

Did it work? If you run the app locally, Flask will start a local server. The code below should work on that local host.

Explanation of the code:

  • Line 3: This is the JSON formatted data we want to POST to the API endpoint. In this case we are sending the numbers 5, 8, and 15. I made the keys are “0”, “1”, “2”, but they could be anything for the purposes of this app.
  • Line 9–10: This is the url for my endpoint. Line 9 is to my hosted app on Heroku if you want to try it out, and line 10 is your local host. Check to make sure your local address matches the code.
  • Line 12: This line posts the JSON data to the specified URL and saves the response.
  • Line 13: The API response can read using the text attribute.
  • NOTE: Be aware that the trailing slash on the url needs to be there when doing a call to an API. Otherwise, there is no redirect to the other server.

I chose to host my API on Heroku. I took the extra steps of adding the requirements.txt and Procfile required by Heroku, deployed it there. See my previous tutorial below for help on that part if you want to host your own API (for free).

So now I have the code working locally, and we have it remotely hosted. We then used Postman.com to try and test out the API against the JavaScript fetch… it didn’t work. I tried it again using plain JSON… it didn’t work. 😧

Cross-Origin Resource Sharing (CORS)

This is why it wasn’t working…

Mozilla explains it better than me:

Cross-Origin Resource Sharing (CORS) is an HTTP-header based mechanism that allows a server to indicate any other origins (domain, scheme, or port) than its own from which a browser should permit loading of resources. CORS also relies on a mechanism by which browsers make a “preflight” request to the server hosting the cross-origin resource, in order to check that the server will permit the actual request. In that preflight, the browser sends headers that indicate the HTTP method and headers that will be used in the actual request.

You can make a Flask app without using CORS. Many apps you build have everything happening on the same server, and they don’t need CORS. However, in the case of an API or an application that requires an outside request to have POST access to your server, we need to add CORS. The default behavior is to block requests so that we don’t have malicious scripts being run on our server. However, using CORS, we can allow select requests through.

To use CORS with Flask, we first install the flask_cors library.

pip install flask_cors

The flask_cors documentation is quite good. It still took me a significant amount of time to arrive at the working code below. I will explain what we changed from the original API to get it working with CORS.

Explanation of the code changes:

  • Line 6: Taken directly from the flask_cors doc. This adds CORS to our app.
  • Line 9: Add a method called OPTIONS to our route. This is how we handle the preflight OPTIONS request needed to grant access to incoming API requests. Basically, the app has to give permission before granting the external request.
  • Line 10: Adding this cross_origins decorator to my route adds CORS on this route at it’s most permissive level. If you need additional security or want to limit the access, there are additional parameters to do that with cross_origins() .
  • Line 12–13: Add a condition to catch the OPTIONS method “preflight”. The preflight just does a permissions check before executing the fetch. The call to the function will build my preflight response.
  • Line 29–34: This function creates my preflight response. I use Flask’s make_response() function to build a a header response which allows all access on this route.

Shout out to Neils B. from Denmark on this stackoverflow response. 🇩🇰

Test the API Response with CORS

Okay, now that we have CORS added to our API, we can run our code again to see what we get. When I run my API test code (from way up above), I get the following response:

{
“results”: [
25,
64,
225
]
}

That’s what I expected (the squares of 5, 8, and 15). Another useful tool for testing the API is the very popular Postman.com. My effort with Postman looked like this:

Postman response from my API

Now we have an API that can receive requests and send responses to our front-end.

Our Project

I wouldn’t want to leave without showing off the app we made. It’s unfinished, but functional (hey, it’s only two people on two day hackathon!)

We chose to make a college recommendation system. When I was a high school teacher, I noticed my students spending countless hours browsing through websites looking for schools to apply to. My students, on average, applied for about 15 colleges!!

Our app points you in the right direction by returning a handful of colleges you might like based on your current “Reach, Target, Safety” school selections. It uses over 200 coded features (selected from over 2000) taken from the US Government’s College Scorecard.

The building of the model might be a different article, but you should try it out! (it’s a work in progress, but pretty cool. See if it works for you.)

https://collegereco.com

Wrap up

I was super excited to finally get this working. After searching long and hard for a resource that would show the steps for creating an API like this, I ultimately ended up having to write it myself.

If you find it useful, I would love to hear from you, or see what you did with it. If you see errors or omissions, or just want to say hi, please leave a comment.

Good Luck! ☘️

--

--