Making a Todo app from a beginners perspective.Intro to FastAPI:
Why FastAPI?
You obviously might be thinking, “Why another framework? what’s wrong with the one which already exist? How is this any better?”
Firstly, It’s fast both in development time and in speed. I mean it has fast in the name, it has to justify its name, right? How fast? It is Very high performance, on par with NodeJS and Go (thanks to Starlette and Pydantic). Such speeds are not imaginable for flask and django.
Independent TechEmpower benchmarks show FastAPI applications running under Uvicorn as one of the fastest Python frameworks available, only below Starlette and Uvicorn themselves (used internally by FastAPI). To get more info, go to the benchmark section of the docs.
Well, to answer that, we can just look at the excellent FastAPI docs.
Still not convinced? I’ll let Sebastián Ramírez (the developer behind this awesome framework) do the work, just take a look.
Now that you are convinced, Let’s discuss what this article is?
What is this article?
This article is one where I am writing in which we will make a simple Todo List app with FastAPI for backend.
Note: I am in no way an expert and this series of articles are not intended as a complete guide to either FastAPI, I am a student and thus we will learn together here and that’s the tone in which this article is gonna be.
All the code of this tutorial series can be found here.
We are gonna use SQLite for the database so that we aren’t caught up with the setup work.
Let's Get Started
First Steps: Making the Hello World App
First, let’s install FastAPI, uvicorn (we need this to host the server) and sqlalchemy (this is the ORM we are going to use)
pip install fastapi uvicorn sqlalchemy
Note: I would recommend using a virtual environment for this.
Next, let’s just make a simple Hello World App in order to get started
To run this, we use the following command
uvicorn main:app --reload
Let’s break this down. First, we import FastAPI class from fastapi and create an instance of it called app. Next, we define a route using the app.get(“/”) decorator. Then we define an asynchronous python function called index and return a python dictionary.
On running the command in terminal and accessing PORT 8000 on the machine, I get the following result.
FastAPI also auto-generates docs, just go to http://localhost:8000/docs to look at them.
Setting up the project structure
Now make a folder and make the file structure as shown.
├── app
│ ├── crud.py
│ ├── db.py
│ ├── models.py
│ └── schemas.py
└── main.py
First, we need to make a db.py folder in order to handle sessions and import the base class
Here, we import the create_engine function and use it to create an instance of the engine which will manage all sessions and connections. We also import the declaritive_base class which will act as the base class for all the models in the database. Now we import the sessionmaker class in order to create connection sessions to the database.
Now, let’s define the model and make the table for the todos in the models.py
Here, we create a Todo class which is subclass of the Base class, this defines the tables in the database. Each todo will have an id, content, a boolean called done and a created field which contains the date created.
Now comes the fun part, FastAPI uses this package called pydantic in order to lots of stuff like type checking and auto-generating docs etc. This is a really cool package, I recommend having a look at its docs.
Initially, I was really confused about this package, so I just conceptualized that theses classes are like gatekeepers in this scenario, they define what data is allowed to go out in the responses and what data is allowed to come in. I can’t say that this is the best and exact explanation but this surely helped me grasp it.
Breakdown time!!
We import datetime. Next, we import BaseModel from pydantic. This class is the base class for all the pydantic models.
Now you might be thinking, why are there 3 classes for a single table and why is there a TodoCreate if it is exactly the same as TodoBase.
So, we generally have multiple classes as shown in fastapi in order to define what is allowed as input and what is allowed as output. And I just made the TodoCreate class to future proof the code.
And that “orm_mode=True” you see, it’s a pydantic feature that makes it easy to use with ORM’s (Object Relational Mapping). You can read more about it here.
Ok ok, I know you wanna move on, but there is one more small detail,
you see the “done: bool = False”, the “= False” here basically gives default value.
Moving On (finally!), we will create some basic crud functions that will help us doing operations on the data.
Here, we make 3 functions, get_todos which will we used to get all the todos from the database. This function also has skip and limit parameters which will be used to implement pagination. The other function create_todo is used to add todo into the database. the db.commit() commit changes (obviously) and db.refresh() refreshes the value in the variable. The update_todo function updates the todo status.
Now, you may have noticed that there is a db named parameter in all of the functions I didn’t talk about. This parameter is of type Session, thus is used to pass the database session instance in the function in order to access and manipulate the data.
Finally, we write the main.py file to define the routes utilizing all the work we have done till now.
Now this last file has a lot to talk about in it. Let’s start from the top
the models.Base.metadata.create_all(bind=engine) creates the tables that we have defined.
Normally you would probably initialize your database (create tables, etc) with Alembic. And you would also use Alembic for “migrations” (that’s its main job).
A “migration” is the set of steps needed whenever you change the structure of your SQLAlchemy models, add a new attribute, etc. to replicate those changes in the database, add a new column, a new table, etc.
You can find an example of Alembic in a FastAPI project in the templates from Project Generation — Template. Specifically in the
alembic
directory in the source code.
Next, we create a Dependency function. FastAPI has a very powerful but intuitive Dependency Injection system.
In our case, it is a function that gets called for every request in order to get database connections. These can be used for may other things, have look at the docs to learn more.
Next, we create 3 routes in order to get, create and update todos.
And that’s it! Our backend is ready! Go play with them in the auto-generated API docs.
Ending
I hope this article helped you. If you wanna have a discussion about any doubts you have, feel free to tweet me @kavii_suri and we’ll figure it out together!
There are some concepts that may need further reading, I wud recommend to read the docs for them. In particular, Dependency Injection and Pydantic models are some concepts that were hard to grasp for me.
Happy Coding!