How to Build an API in Python (with Flask & RapidAPI)

RapidAPI Team
Aug 20, 2019 · 11 min read

If you are reading this article, you are probably familiar with the possibilities that open up when you use an API (Application Programming Interface).

By using one of the many public APIs out there, you can expand the functionality of your application or enrich it with the necessary data.

But what if you have created your own unique functionality that you want to share with the community?

The answer is to create your own API.

Related: How to Use an API with Python

While this may seem like a daunting task at first glance, it’s actually quite easy.

We’ll break down how to do this with Python in the steps below.

Requirements

To create an API, we will use:

We will also need Flask-RESTful, an extension for Flask which enables rapid development of REST API with minimal setup. Installation is carried out by the command:

pip install flask-restful

Before We Get Started

We are about to develop a RESTful API that implements the basic CRUD functionality.

To fully understand the problem, let’s dive into these 2 terms mentioned above:

What is REST?

REST API (Representational state transfer) is an API that uses HTTP requests for communication.

REST APIs must follow certain constraints. Here are a few:

  • Client-server architecture — the client handles the user interface, and the server handles the backend and data storage. Client and server are independent, and each of them can be replaced separately.
  • Stateless — no data from the client is stored on the server-side. The session state is stored on the client-side.
  • Cacheable — clients can cache server responses to improve performance.

What is CRUD?

CRUD is a programming concept that identifies four basic actions ( create, read, update, and d elete) that can be performed on the data.

In the REST API, Types of Requests or Request Methods are responsible for these actions:

  • POST: Create action. Adds new data to the server. Using this type of request, we can, for example, add a new post to a blog.
  • GET: Read action. Retrieve information. This is the most common type of request. Using it we can, for example, get a list of blog posts.
  • PUT: Update action. Changes existing information. For example, using this type of request, it would be possible to change the text of the existing article.
  • DELETE: Delete action. Deletes existing information, such as a blog post, that we are no longer interested in.

Now that we understand the basic terms, we can begin to create our API.

Implementation

Let’s create a repository of quotes about artificial intelligence (AI).

AI is one of the fastest-growing branches of human activity today, and Python is a popular tool for working with AI.

With this API, any Python developer can quickly retrieve a statement about artificial intelligence and be inspired for new achievements.

If the developer has his/her own worthwhile thoughts on this topic, then he/she will be able to add them to the repository.

Let’s start with importing the required modules and setting up the Flask application:

from flask import Flask
from flask_restful import Api, Resource, reqparse
import random
app = Flask(__name__)
api = Api(app)

In the indicated code snippet, Flask, Api and Resource are the classes that we will need to work with.

Reqparse is Flask-RESTful request parsing interface. We will also need the random module to display a random quote.

Next, we will create a repository of quotes about AI.

Each entry in the repository will contain:

  • a numerical id,
  • the name of the author of the quote,
  • and the quote itself.

Since this is a training example, we will store all entries in the Python list. In a real-world application, we would probably use a database instead.

ai_quotes = [
{
"id": 0,
"author": "Kevin Kelly",
"quote": "The business plans of the next 10,000 startups are easy to forecast: " +
"Take X and add AI."
},
{
"id": 1,
"author": "Stephen Hawking",
"quote": "The development of full artificial intelligence could " +
"spell the end of the human race…. " +
"It would take off on its own, and re-design " +
"itself at an ever increasing rate. " +
"Humans, who are limited by slow biological evolution, " +
"couldn't compete, and would be superseded."
},
{
"id": 2,
"author": "Claude Shannon",
"quote": "I visualize a time when we will be to robots what " +
"dogs are to humans, " +
"and I’m rooting for the machines."
},
{
"id": 3,
"author": "Elon Musk",
"quote": "The pace of progress in artificial intelligence " +
"(I’m not referring to narrow AI) " +
"is incredibly fast. Unless you have direct " +
"exposure to groups like Deepmind, " +
"you have no idea how fast—it is growing " +
"at a pace close to exponential. " +
"The risk of something seriously dangerous " +
"happening is in the five-year timeframe." +
"10 years at most."
},
{
"id": 4,
"author": "Geoffrey Hinton",
"quote": "I have always been convinced that the only way " +
"to get artificial intelligence to work " +
"is to do the computation in a way similar to the human brain. " +
"That is the goal I have been pursuing. We are making progress, " +
"though we still have lots to learn about " +
"how the brain actually works."
},
{
"id": 5,
"author": "Pedro Domingos",
"quote": "People worry that computers will " +
"get too smart and take over the world, " +
"but the real problem is that they're too stupid " +
"and they've already taken over the world."
},
{
"id": 6,
"author": "Alan Turing",
"quote": "It seems probable that once the machine thinking " +
"method had started, it would not take long " +
"to outstrip our feeble powers… " +
"They would be able to converse " +
"with each other to sharpen their wits. " +
"At some stage therefore, we should " +
"have to expect the machines to take control."
},
{
"id": 7,
"author": "Ray Kurzweil",
"quote": "Artificial intelligence will reach " +
"human levels by around 2029. " +
"Follow that out further to, say, 2045, " +
"we will have multiplied the intelligence, " +
"the human biological machine intelligence " +
"of our civilization a billion-fold."
},
{
"id": 8,
"author": "Sebastian Thrun",
"quote": "Nobody phrases it this way, but I think " +
"that artificial intelligence " +
"is almost a humanities discipline. It's really an attempt " +
"to understand human intelligence and human cognition."
},
{
"id": 9,
"author": "Andrew Ng",
"quote": "We're making this analogy that AI is the new electricity." +
"Electricity transformed industries: agriculture, " +
"transportation, communication, manufacturing."
}
]

Now let’s create the Quote resource class.

It will determine the operation of the endpoints of our API. Inside the class, we will define four methods (remember: get, post, put, delete).

Let’s start with the GET method.

With this method, we can get a specific quote by specifying its id or get a random quote if the id is not specified:

class Quote(Resource):
def get(self, id=0):
if id == 0:
return random.choice(ai_quotes), 200
for quote in ai_quotes:
if(quote["id"] == id):
return quote, 200
return "Quote not found", 404

The GET method returns a random quote if id contains a default value (that is, id was not specified when the method was called).

If the id is specified, then the method iterates through all the records in the quotes repository and returns the result that matches the specified id.

If the record cannot be found, the method returns the corresponding message (“Quote not found, 404”).

Note that the method returns a HTTP Status Code 200 to each response if the request is successful, 404 if the record is not found.

Next, let’s create a POST method to add a new quote to the repository.

This method will receive the identifier of the new quote at the input. Also, POST will use reqparse to parse the parameters that will go in the body of the request (author and quote text).

def post(self, id):
parser = reqparse.RequestParser()
parser.add_argument("author")
parser.add_argument("quote")
params = parser.parse_args()
for quote in ai_quotes:
if(id == quote["id"]):
return f"Quote with id {id} already exists", 400
quote = {
"id": int(id),
"author": params["author"],
"quote": params["quote"]
}
ai_quotes.append(quote)
return quote, 201

In the code snippet above, the POST method accepts id of the quote. Then using reqparse, it gets author and quote from the request and stores them in params dictionary.

If a quote with the specified id already exists, then the method returns the corresponding message and a 400 status code.

If a quote with the specified id has not yet been created, the method creates a new record with the specified id and author and quote parameters. Then it adds the record to ai_quotes list, and then returns a record with a new quote and a 201 status code.

Now we will create the PUT method to modify the contents of an existing quote in the repository:

def put(self, id):
parser = reqparse.RequestParser()
parser.add_argument("author")
parser.add_argument("quote")
params = parser.parse_args()
for quote in ai_quotes:
if(id == quote["id"]):
quote["author"] = params["author"]
quote["quote"] = params["quote"]
return quote, 200

quote = {
"id": id,
"author": params["author"],
"quote": params["quote"]
}

ai_quotes.append(quote)
return quote, 201

Similarly, with the previous example, the PUT method takes id at the input and then parses the quote parameters using reqparse.

If a quote with the specified id exists, the method will update it with parsed parameters and return an updated quote with the 200 Status Code.

If there is no quote with the specified id yet, a new record will be created and returned with 201 Status Code.

Finally, let’s create a DELETE method to remove a quote that no longer seems inspirational to us:

def delete(self, id):
global ai_quotes
ai_quotes = [qoute for qoute in ai_quotes if qoute["id"] != id]
return f"Quote with id {id} is deleted.", 200

The DELETE method receives the quote id at the input and updates the ai_quotes list through global scope using list comprehension.

Now that we have created all the methods in our Quote resource, all we need to do is to add a resource to our API, specify its routes, and run our Flask application:

api.add_resource(Quote, "/ai-quotes", "/ai-quotes/", "/ai-quotes/<int:id>")
if __name__ == '__main__':
app.run(debug=True)

Our REST API Service is now ready!

Now we can save our code in the app.py file and run it in the console with the command:

python3 app.py

If everything is in order, then we should see something like the following lines:

* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: XXXXXXX

Testing the API

Now that we’ve created our API, let’s test it!

We can test our API service using the curl console utility or Insomnia REST client or by publishing it on RapidAPI.

Publishing your API

RapidAPI is the world’s largest marketplace with over 10,000 APIs (and over 1,000,000 developers).

Not only does RapidAPI provide a single interface for working with third-party APIs, but it also provides the ability to quickly and seamlessly publish your own API.

To publish our API on RapidAPI, we need to first publish it on some server on the Internet.

In our case, let’s use Heroku. Publishing an API on Heroku is quite simple ( learn more here).

How to Publish your API on Heroku

1. Install Heroku

First, we’ll need to register for a Heroku account and install the Heroku Command Line Interface (CLI) with the following command (works with Ubuntu 16+):

sudo snap install heroku --classic

Then log in to the Heroku CLI:

heroku login

2. Add the Necessary Files

Now, let’s add the necessary files for publication to the folder within our app:

  • requirements.txt with a list of necessary Python modules
  • Procfile, which explicitly declares what commands should be executed to start our app
  • .gitignore, to exclude files we don’t need on the server

Our requirements.txt file will contain the following lines:

flask
flask-restful
gunicorn

Please note that we have added gunicorn (Python WSGI HTTP Server) to our list, since it is necessary to run our app on the server.

Procfile will contain:

web: gunicorn app:app

and .gitignore will contain the following:

*.pyc
__pycache__/

Now that we’ve created the necessary files, let’s initialize a git repository and commit:

git init
git add .
git commit -m "First API commit"

3. Create a new Heroku application

heroku create

And then finally push our master branch to the Heroku remote repository:

git push heroku master

Now we can start and open our API Service using the commands:

heroku ps:scale web=1
heroku open

Our API will now be accessible at: https://your-random-heroku-name.herokuapp.com/ai-quotes/

How to Add Your Python API to RapidAPI’s Marketplace

Now that our API service is published on Heroku, we can now add it to RapidAPI. You can find detailed documentation here for getting started:

1. Create a RapidAPI Account

Image for post
Image for post

First, sign up for a free RapidAPI account. You can do so with Facebook, Google, or even your Github account.

2. Add your API through the Provider Dashboard

Head on over to https://provider.rapidapi.com and click on “Add New API”.

From here, you’ll need to enter general information about your API.

After clicking ‘Add API’, the API overview definition page will appear. Here we can add some more information about our API.

Now, we can either manually enter your API’s endpoints or upload a swagger file using OpenAPI.

Let’s define the endpoints of our API on the Endpoints page. In our case, endpoints match the CRUD concept (get, post, put, delete).

Create a GET AI Quote endpoint that will return a random quote (if the id parameter has a default value) or a quote corresponding to a specific id.

To create an endpoint, click the “Create Endpoint” button.

Repeat this process for all other API endpoints.

And that’s it! Congratulations, you’ve published your API!

If all goes well, you’ll have an API page that looks like this:

Conclusion

In this article, we studied the process of creating our own RESTful API Service in Python, the process of publishing the API on the Heroku cloud platform, and then adding it to RapidAPI Catalog.

While we explored the basic principles of developing an API, we did not dive into the issues of security, fault tolerance, and scalability of the API.

In real (production) conditions, these issues should definitely be taken into account.

Related Resources

Originally published at https://blog.rapidapi.com on August 20, 2019.

The Era of APIs

What happens when every app or software can talk to each…

RapidAPI Team

Written by

Learn more at https://blog.rapidapi.com/. Head over to https://rapidapi.com to sign up for a FREE account to begin using APIs!

The Era of APIs

What happens when every app or software can talk to each other? Let’s find out. By the makers (and friends) of RapidAPI.

RapidAPI Team

Written by

Learn more at https://blog.rapidapi.com/. Head over to https://rapidapi.com to sign up for a FREE account to begin using APIs!

The Era of APIs

What happens when every app or software can talk to each other? Let’s find out. By the makers (and friends) of RapidAPI.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store