FastAPI Tutorial: How to create APIs using Python?
Application programming interfaces, or APIs, are a crucial part of making your product accessible to a wide range of people. I’ve using Express to create all my APIs for the longest time, and after trying FastAPI for a few weeks I can comfortably say that I really like its simple nature. You will learn what FastAPI is, and the fundamentals of FastAPI in this article, along with how to utilize it to quickly construct web APIs that automatically adhere to best practices. Throughout the process, you will learn everything while also building a simple Pizza API!
Installation
Before doing anything else, let us install all the prerequisites. This article assumes you have Python installed on your system, if not you can download and install Python from their official website. First of all, let us install FastAPI with the following command,
pip install fastapi
Code language: Bash (bash)
Server
We will also need a server for serving our API. We can use either uvicorn
or hypercorn
, both are great options and achieve the exact same thing. You can install either of them using the following commands,
pip install uvicorn
Code language: Bash (bash)
Or,
pip install hypercorn
Code language: Bash (bash)
That is all we will need, for now, let us get started building the API!
Getting Started
Let’s first create a base route that produces a straightforward JSON response before we create the pizza routes.
Make a main.py file and a directory for your project. This is how your code should look (feel free to customize the message to your liking!).
# main.py
# Importing FastAPI
from fastapi import FastAPI
# Initializing the app
app = FastAPI()
# ? GET operation at route '/'
@app.get('/')
async def index():
return {"greeting" : "Welcome to Paul's Pizza!"}
Code language: Python (python)
Running the live server
The following command can be used to run the live server with uvicorn:
uvicorn main:app --reload
Code language: Bash (bash)
You’ll see that the word “main” in the code relates to the filename, and the word “app” is the name of the FastAPI instance we previously built.
Now, if you use your browser to access localhost:8000, you will see the JSON response as follows:
Some things to note
- The code
@app.get("/")
directive informs FastAPI that the function that follows is in charge of handling requests that go to,- The path “/”
- utilizing the HTTP get method. Other HTTP methods, such as put, post, or delete, can also be used.
- Using Swagger, FastAPI automatically produces API documentation. Visit the documentation at
localhost:8000/docs
. How cool is that? You can even test your API endpoints from here!
At this point, your API docs should look like this with only the ‘/’ route,
Another cool thing is that FastAPI automatically translates Python dicts, lists, or other primitive types or Pydantic models to the appropriate JSON format.
That is enough with the basics, let’s create our Pizza API now!
Create the API
Now let’s build a basic API that allows us to retrieve and add new pizzas to a list of pizzas with various qualities in, say, /pizzas.
Setup
Now, we could establish a connection to any kind of database we want, but let’s keep things simple and use an in-memory list that we can access and alter.
Create a new variable called “db” and fill it with the information about the pizzas below.
# main.py
#... code before
db = [
{
'id': 1,
'name': 'Chicago/Deep-Dish Pizza',
'toppings': ['Mushrooms', 'Cheese', 'pepperoni', 'Tomatoes', 'Onions']
},
{
'id': 0,
'name': 'Neapolitan Pizza',
'toppings': ['Mozzarella cheese', 'Tomatoes', 'Basil']
},
]
#... code after
Code language: Python (python)
Get all pizzas
We can just return the database list we created previously, which contains a list of every pizza, in response to a GET
request at /pizzas.
# main.py
# ...
# gets all pizzas in db
@app.get('/pizzas')
async def index():
return db
# ...
Code language: Python (python)
We can now see the list of pizzas we made previously by visiting localhost:8000/pizzas
.
Great! The route is also available in the documentation at localhost:8000/docs
.
Get a single pizza with an ID
Let’s establish a route that points to localhost:8000/pizzas/<id>
and returns information about the pizza with the given id. Path parameters will be used here.
# main.py
# ...
# getting a single pizza by id
@app.get('/pizzas/{id}')
async def get_pizzas(id):
for pizza in db:
if(pizza['id'] == int(id)):
return pizza
return {"error": "No Pizza was found with id: " + id}
# ...
Code language: Python (python)
The most important thing to keep in mind is that your function will receive the value of the path parameter id
as an argument, which will be used to return the pizza object with the specified id in this case.
Now if you visit a route with a valid id like localhost:8000/pizzas/0
, you’ll see a response similar to this,
Great job! Two different kinds of pizza aren’t enough, though. Let’s explore how we can add more pizzas to our list by making a post route!
Add a new pizza with POST
For the purpose of adding new pizzas to our list, let’s establish a post route on /pizzas
. To do this, we must first specify the request body’s data model or the type of data we expect to get from the request.
Here, we have a pretty basic data model. We have a string that serves as the name of our pizza and a list of available toppings. We’ll dynamically create a new id for the pizza. By deriving the BaseModel
class from Pydantic
, we define the data model.
# main.py
#...
# ?importing BaseModel and needed types
from pydantic import BaseModel
from typing import List
# ? Creating the pizza model
class Pizza(BaseModel):
name: str
toppings: List[str]
#...
Code language: Python (python)
This Pizza class is now available to us as a type for our request body. The post method will be created as follows:
# main.py
#...
# ? POST request for /pizzas
@app.post('/pizzas')
async def post_pizza(pizza: Pizza):
# converting the object to dict
my_pizza = pizza.dict()
# add a unique id
my_pizza['id'] = db[-1]['id'] + 1
# Add to our db and return
db.append(my_pizza)
return my_pizza
#...
Code language: Python (python)
By selecting the Try it out
button next to the POST route we just constructed and providing the request body, you can test this post route directly from our API documentation at localhost:8000/docs
.
We can see that our new pizza has been added to the list and given an ID if we execute this request and go to localhost:800/pizzas
.
What next?
Our API is now looking great! We have a get
method for getting all the pizzas, another get
method for getting one pizza with its ID, and also a post
method for adding new pizzas to our list of pizzas. This is looking much like a usual API, but what if we made a mistake while adding a pizza? There’s no way to edit a pizza you just added. It is time for you to use what you’ve just learned and create a put
route for editing a pizza with its id. Notice how we cannot delete the entries we add either? What if we are no longer making a specific pizza? That is a problem, try to add a delete
route for removing a specific pizza with an id as well!
If you wish to refer to the whole file we’ve been working on, I’ve created a Gist you can look at.
Conclusion
And with that, we are done! With very little code, you’ve managed to construct a straightforward API that takes GET and POST queries. FastAPI is a modern and high-performance framework for building APIs and is also very straightforward and easy to learn. If you enjoy what you see and want to learn more about FastAPI, I advise reading the FastAPI User Guide for a more thorough examination of the most crucial features. Try implementing a PUT and DELETE route for the pizzas as a starter!
If you have any questions regarding this article or want to talk about anything technology, you can find me on Twitter. Thank you for reading!
Sharing is caring
Did you like what Supantha Paul wrote? Thank them for their work by sharing it on social media.
No comments so far
Curious about this topic? Continue your journey with these coding courses: