FastAPI Tutorial (Part 1) - The Basics

14 min read
Table of Contents
- Introduction
- Tutorial Series Contents
- Disclaimer
- Requirements
- Project files and repo
- What we’re building
- What is FastAPI?
- Project Setup
- Using starter template
- Create basic project from scratch
- Quick Recap
- Let’s start our project API
- Project requirements in details
- Books related endpoints
- FastAPI Router
- Connect router
- FastAPI - API Docs
- Next steps
Introduction
Welcome to the FastAPI tutorial series. This is part 1 of a series of posts where I aim to show how to build a Book store API using the Python framework FastAPI.
This series is aimed to beginners using FastAPI, but if you have previous knowledge you can contribute to it too. Each post will build on the previous, however, I did my best to divide it in a way that if you know about FastAPI and are only interested in one part you can jump to it directly.
I think FastAPI’s docs are really good and you can learn to use the framework on your own just by checking on them. That said, I think there are few things that could be explained better for beginners and that’s one of the reasons I decided to create this series.
Tutorial Series Contents
- Part 1: The Basics - Getting started, create base endpoints.
- Part 2: Routes - CRUD operations, Url and query params & returning data to the client, CORS.
- Part 3: Data Validation - Pydantic schemas, response models and error handling. (comming soon…)
- Part 4: Databases - SQL Databases and ORM’s (SQLAlchemy). (comming soon…)
- Part 5: Authentication - User authentication via JWT (register, login, logout password reset). (comming soon…)
Disclaimer
As with most of my guides, I do not claim to be an expert in the topic. I however, like sharing what I learn, and also, I’m a firm believer that you learn more when you teach or share what you know. That said, I do take the time and effort to do a lot of research on the topic in order to provide valid and updated info that can be useful for others, specially for beginners.
In any case, if you find an error in the information, or something you thing could be explained or approached in a better way, I would appreciate you letting me know so I can fix any mistake or even encourage you to make a PR on the project main repo. That way, we can all work together to provide the best information possible to others.
Requirements
Although this is a series aimed for beginners, it’s important to have a basic knowledge on at least the following topics:
- Python programming language (variables, dictionaries, lists, functions, modules)
- API’s (HTTP methods, endpoints)
- Back-end development
For this tutorial series, I’m using the following tools and versions:
- Python: 3.10.2
- FastAPI: 0.75.0
- Uvicorn: 0.17.6
I’m also using Poetry as my dependency manager, but that’s just a personal preference and is not required to follow along. If you prefer, you can use Pip
to manage dependencies.
Project files and repo
I’ve created a Github repository to storage all the project files. You can check it here. Each part of the tutorial (post) has a branch so you can check the code for each post. Inside the main
you’ll see the updated code (the final version).
There is also a starter
branch with the starter files if you’re following along.
What we’re building
By the end of the tutorial, we’ll have a complete API for a fictional online book store. Users will be able to see all the available books, single book details, authors, register, login/logout, make orders.
The API will handle database integration, user register, handle request errors and expose a fully documented API by taking advantage of Swagger-UI capabilities.
What is FastAPI?
If you’re reading this, chances are, you already know what FastAPI is. But just in case you don’t know or haven’t seen the documentation yet, let’s see a basic definition for it.
FastAPI is a fast, lightweight Python framework to build, well, API’s. Think of it like something similar to Flask or Django. That said, FastAPI offer some key features that differentiate it from other python frameworks, like, fast and enjoyable development experience, high-performance, minimalistic and much more. You can read more on FastAPI official docs.
Project Setup
To start with our project, first, let’s create our development setup. If you’re following along, there are two ways you can get started. You can either use the starter code by cloning or downloading the starter Github repo (recommended). Or if you prefer, you can get started by creating the project from scratch.
Let’s see both alternatives next.
Using starter template
If you downloaded/cloned the starter project you can find a main.py
file inside with the following content:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def index():
return {"message": "Hello World"}
Before running the local development server, make sure to create a virtual environment for your application and install the dependencies. After creating your environment, activate it and install the dependencies. If you’re using Poetry you can run poetry install
, alternatively, you have a requirements.txt
inside your project folder from which you can install the dependencies.
To install dependencies with pip
, run:
$ pip3 install -r requirements.txt
After installing dependencies, you can run the local server using the following command in your terminal:
$ uvicorn app.main:app --reload
In your browser, go to http://localhost:8000
, if you see the following result, you’re good to go.

You can skip the next section and go to Quick Recap.
Create basic project from scratch
If you want to create the project from scratch, just follow this instructions:
- Create a new folder and name it
fastapi-tutorial
or use the name you prefer. - Inside the folder we will create a dependency manager file. If you want to use
pip
create a file namedrequirements.txt
. Alternatively you can use Poetry to manage dependencies by typing in the terminalpoetry init
and follow the instructions (you have to install poetry first), when you’re prompted to define your dependencies you can selectno
, we will define them in the next step. Once you finish your poetry setup a newpyproject.toml
file will be created in your project directory root. - Before installing dependencies remember to create your virtual environment. If you’re using
pip
you can create your environment by typing the following in your terminal:
$ python3 -m venv venv
# Activate the environment
$ source venv/bin/activate # for mac users
$ venv\Scripts\activate.bat # for windows users
If your using Poetry you can create a new environment by typing on your terminal:
$ poetry shell
This will create a new environment or activate it if there is one already. You can read more about python virtual environments here. Remember in your text editor to select this virtual environment as your python interpreter.
In any case, once you have activated your virtual environment we can now install our dependencies.
- Now that we have an active virtual env, let’s install project dependencies.
$ pip3 install fastapi
$ pip3 install uvicorn
# or if using poetry
$ poetry add fastapi uvicorn
I’m also using the black
library as a code formatter, this is an optional step but if you want you can install it the same way as the other dependencies (if you’re using Poetry you can install black
as a dev dependency by adding the flag --dev
before the package name).
Finally, in your root directory create a folder called app
(we will talk about why doing it this way later), inside this folder create this two files: __init__.py
and a main.py
file and add the following code to the main.py
file and run it.
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def index():
return {"message": "Hello World"}
Run the server like this:
$ uvicorn app.main:app --reload
If everything went ok, weather you created the project from scratch or copied it from Github, you should see the following result of running your server by navigating in your browser to http://localhost:8000
:

We should end up with the following folder structure.
fastapi-tutorial/
├── .vscode/ --> Optional: Only if you have any project specific setting
├── app/
│ ├── **init**.py
│ └── main.py
├── .gitignore
├── main.py
└── pyproject.toml
If you’re not using poetry, you should have a file named requirements.txt
instead of
pyproject.toml
.
Also, if you’re using poetry the default config will create your venv
folder in a location different from your project root. You can change this behavior by typing the following command in your terminal:
$ poetry config virtualenvs.in-project true
Quick Recap
So far, we’re just getting started with our setup, but, before starting with the main project, let’s quickly recap what we’ve done up to this point.
- First, we created a virtual environment for our application. We did this with either using poetry or with simple
python/pip
. - Then we install the main project dependencies: FastAPI and Uvicorn. Later we will install other dependencies, but, for the moment this is enough.
- Finally we create a
main.py
file inside our project’s root. We end up with the following:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def index():
return {"message": "Hello World"}
I’m not going to go into too much detail about this code, because I think the docs do a really good job explaining line by line. But basically first, we import the FastAPI
class, then create an instance of the class and we call it app. Finally we create a function called index
(you can use the name you prefer for this), this function is using a python decorator with the app
instance we created which will allow us to use this function to return something to the browser (create an endpoint). In this case we’re returning a dictionary with a message
key and a value of Hello World
.
If we run our uvicorn
server, we see the following result on the default route (http://localhost:8000
):
$ uvicorn app.main:app --reload

By using the --reload
flag in the uvicorn
command we’re telling uvicorn
to watch our project
for any change and reload the server automatically.
Let’s start our project API
As I mentioned before we were just getting our setup ready. I wanted to take some time in this part to make sure everybody is starting from the same place.
Now, let’s start our main API.
Project requirements in details
First, let’s define our project requirements so it is easier to understand our end goal.
The client application should be able to perform all CRUD operations for the books stored in the database (Create, Read, Update, Delete).
Also, the client should be able to authenticate any user, and users should be able to register, login, logout, reset password, etc.
Books related endpoints
We’re going to start working with our books endpoints. For this, let’s add two new folders to our application.
fastapi-tutorial/
├── .vscode/
├── app/
│ ├── endpoints/ --> NEW
│ │ ├── **init**.py
│ │ ├── api.py
│ │ └── books.py
│ ├── **init**.py
│ └── main.py
├── .gitignore
├── main.py
└── pyproject.toml
First, let’s work with the endpoints
folder, inside it, let’s create the 3 files you see in the project tree __init__.py
, api.py
and books.py
.
Remember that by adding a __init__.py
file to our folders, python will see this folders as a
module, which will make easier to import from them.
FastAPI Router
FastAPI allows us to create separated routers for our application, that way it’s easier to separate our project in different files. For example, for our application, we’ll have routes for books
, users
, authors
; now, instead of creating 1 file for all our endpoints, with FastAPI router we can create 1 file for each part of our routing system (1 file for books, 1 for users, and so on…). To do this, inside our books.py
file:
from fastapi import APIRouter
# Instanciate a new fastapi router
router = APIRouter()
# Add mock data
books = [
{"id": 1, "title": "book 1", "price": 16.99},
{"id": 2, "title": "book 2", "price": 12.99},
{"id": 3, "title": "book 3", "price": 9.99},
]
The router
variable has all the properties from the APIRouter
class. This will allow us to create new decorators for each of the required HTTP methods (GET
, POST
, PUT
, DELETE
). Having this in mind, let’s create a new route for our required methods.
# code above omitted 👆
@router.get("/")
def get_books():
"""Get books from database"""
return books
The first method will be a GET
method to retrieve books from our API. Now before continuing, let’s connect our books
router to the main application and test it.
Connect router
To connect our router, let’s go to the api.py
file created in the same level as our books.py
file. Inside we copy the following code.
from fastapi import APIRouter
from . import books
api_router = APIRouter()
api_router.include_router(books.router, prefix="/books", tags=["Books"])
Let’s review the code:
- First, we create a new
APIRouter
instance calledapi_router
. This will be the main API router. - Next, we add the newly created
books
router to ourapi_router
using the functioninclude_router
and pass thebooks.router
as the first parameter. - The
prefix
param allows to tell the router to base route for this particular router, in our case, since we’re working with books we use/books
as our prefix, - The
tags
params helps to identify this routes in our documentation.
Finally, in our main.py
we import this new router.
# from fastapi import FastAPI
from app.endpoints.api import api_router
# app = FastAPI()
app.include_router(api_router, prefix="/api")
# @app.get("/")
# def index():
# return {"message": "Hello World"}
We included our main router the same way as with the books
router.
By using the prefix="/api"
we’re telling python that all our endpoints will start with the
/api
prefix.
This means that to hit our books endpoints, we’ll have a full Url similar to something like this:
http://my-domain.com/api/books
FastAPI - API Docs
Normally, when we create a new API, we use something like Postman to test our endpoints. One of the many benefits of using of using FastAPI is that the framework makes use of the Swagger-UI library to create our API documentation as we develop it.
To make use of the docs, all we have to do is, in our browser go to http://localhost:8000/docs
. You should see something like this:

You can see, we already have two new endpoints, one GET
for the path /api/books/
and one GET
for our default index
route created in the main.py
file.
You can expand this routes and will see something like this:

You can try this endpoint by clicking on the Try it out
button and then click the Execute
button. You should get a response like this:

You notice, in the response body we get exactly the same 3 dummy books we created on our books.py
file.
You can use this docs to test your entire API. Later we’ll add schemas that will allow us the validate the data we receive and send from our API.
Alternatevily, instead of Swagger docs, you can go to htpp://localhost:8000/redoc
to see other
type of documentation that also will allow you to test your API.
For the purpuse of this tutorial series, we’ll use Swagger docs, but feel free to use any API tester you prefer.
Next steps
At this point we created our API setup, and added a basic endpoint to retrieve all books available in our database.
In the next part of the tutorial, we’ll focus on the rest of the endpoints for our books store. We will see how to get URL parameters, parse the Request body to create new books and add them to our dummy list.