with Python, most individuals speak about Django and Flask. However there’s a more moderen, very speedy possibility that many Python programmers are beginning to love: FastAPI.
FastAPI is constructed on fashionable Python options, utilizing customary kind hints to supply automated information validation, serialisation, and interactive API documentation totally free.
Selecting the correct framework relies on your wants. Django is a full-stack framework, and Flask is understood for its simplicity. FastAPI, then again, is made for constructing APIs. It stands out for its pace, ease of use, and talent to cut back repetitive code.
So, when do you have to select FastAPI to your challenge?
- You’re constructing an API-centric service. FastAPI is designed from the bottom up for this objective.
- You need your code to be your documentation. FastAPI’s automated docs are a game-changer.
- Efficiency is important. FastAPI is among the quickest Python frameworks obtainable.
Whether or not you’re constructing a small microservice or a fancy backend, realizing what FastAPI does greatest will show you how to resolve if it’s best for you. You’ll get essentially the most from this text in case you already know the basics of Python capabilities, HTTP strategies, and JSON.
Putting in FastAPI
You possibly can set up FastAPI with simply the fundamentals, nevertheless it’s greatest to make use of the really useful setup. This fashion, you get every little thing you want from the beginning and don’t have to fret about lacking dependencies later.
Earlier than you start, it’s a good suggestion to create and activate a digital setting. This retains your challenge’s dependencies separate and your system tidy. I take advantage of UV for this, however you should use any software you want. Though I normally work on Home windows, for this instance, I’ll use Ubuntu WSL2 on Home windows. I’ll additionally run the code in a Jupyter Pocket book, which implies including a bit of additional code to deal with Jupyter’s occasion loop, since it will possibly battle with FastAPI’s async options.
tom@tpr-desktop:~$ uv init fastapi
Initialized challenge `fastapi` at `/dwelling/tom/fastapi`
tom@tpr-desktop:~$ cd fastapi
tom@tpr-desktop:~/fastapi$ uv venv
Utilizing CPython 3.13.0
Creating digital setting at: .venv
Activate with: supply .venv/bin/activate
tom@tpr-desktop:~/fastapi$ supply .venv/bin/activate
(fastapi) tom@tpr-desktop:~/fastapi$
To get the complete FastAPI expertise, set up it with the [standard] extras. This contains the FastAPI command-line software and the Uvicorn ASGI server, which you’ll have to run your app.
(fastapi) tom@tpr-desktop:~/fastapi$ uv pip set up jupyter "fastapi[standard]"
Resolved 124 packages in 2.88s
Ready 26 packages in 1.06s
Put in 124 packages in 80ms
+ annotated-types==0.7.0
+ anyio==4.11.0
+ argon2-cffi==25.1.0
...
...
...
+ webencodings==0.5.1
+ websocket-client==1.8.0
+ websockets==15.0.1
+ widgetsnbextension==4.0.14
(fastapi) tom@tpr-desktop:~/fastapi$
To confirm that every little thing is okay, begin up a Jupyter Pocket book and sort within the following code. You must obtain a model quantity in return. Relying on while you run this code, your model quantity will possible differ from mine.
import fastapi
print(fastapi.__version__)
# My Output
0.129.0
We’re now able to construct some purposes.
Instance 1: Hey World
Making a primary FastAPI utility takes only a few traces of code. We’ll begin with a easy “Hey World” message as an instance the framework’s core mechanics. Don’t fear, our apps will change into extra helpful quickly. Sort the next code right into a pocket book cell.
import nest_asyncio
import uvicorn
from fastapi import FastAPI
# Patch asyncio to permit nested use (wanted in Jupyter/Colab)
nest_asyncio.apply()
app = FastAPI()
@app.get("/")
def dwelling():
return {"message": "Hey, World!"}
# Use Config + Server as a substitute of uvicorn.run()
config = uvicorn.Config(app=app, host="127.0.0.1", port=8000, log_level="data")
server = uvicorn.Server(config)
await server.serve()
As talked about beforehand, there’s a bit of additional scaffolding required on this code as a result of I’m operating in a Pocket book setting, which you wouldn’t normally want if operating as a stand-alone Python module. Nonetheless, this small instance reveals a fantastic deal already. You import FastAPI, create an app occasion, and use a decorator (@app.get(“/”)) to inform FastAPI that the house() operate ought to deal with GET requests to the foundation path. The operate returns a easy textual content string.
If you run the code above, you must see output much like this.
INFO: Began server course of [28755]
INFO: Ready for utility startup.
INFO: Software startup full.
INFO: Uvicorn operating on http://127.0.0.1:8000 (Press CTRL+C to give up)
In the event you now click on on the URL within the above output, you must see one thing like this.
Now, let’s construct one thing extra helpful.
Instance 2: A Purposeful To-Do Checklist
Actual-world APIs have to handle information. Let’s develop our code to create a easy in-memory To-Do checklist API that may permit full CRUD operations. This can showcase path parameters, request our bodies, and information validation.
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import Checklist, Optionally available
import uvicorn
import nest_asyncio
import threading
app = FastAPI()
# --- Pydantic Fashions for Knowledge Validation ---
class TodoItem(BaseModel):
id: int
description: str
accomplished: bool = False
class CreateTodoItem(BaseModel):
description: str
class UpdateTodoItem(BaseModel):
description: Optionally available[str] = None
accomplished: Optionally available[bool] = None
# --- Dependency ---
async def common_query_params(accomplished: Optionally available[bool] = None, skip: int = 0, restrict: int = 10):
return {"accomplished": accomplished, "skip": skip, "restrict": restrict}
# --- In-memory "database" ---
todos_db = {
1: TodoItem(id=1, description="Purchase groceries"),
2: TodoItem(id=2, description="Stroll the canine", accomplished=True),
3: TodoItem(id=3, description="Wash the automobile"),
4: TodoItem(id=4, description="Take out the trash", accomplished=True),
5: TodoItem(id=5, description="Watch TV"),
6: TodoItem(id=6, description="Play Golf", accomplished=True),
7: TodoItem(id=7, description="Eat breakfast"),
8: TodoItem(id=8, description="Climb Mt Everest", accomplished=True),
9: TodoItem(id=9, description="Work"),
10: TodoItem(id=10, description="Verify the time", accomplished=True),
11: TodoItem(id=11, description="Feed the canine"),
12: TodoItem(id=12, description="Decide up children from College", accomplished=True),
}
@app.get("/todos", response_model=Checklist[TodoItem])
def get_all_todos():
"""Get all to-do objects."""
return checklist(todos_db.values())
@app.get("/todos/{todo_id}", response_model=TodoItem)
def get_todo(todo_id: int):
"""Get a single to-do merchandise by its ID."""
if todo_id not in todos_db:
increase HTTPException(status_code=404, element="To-do merchandise not discovered")
return todos_db[todo_id]
@app.put up("/todos", response_model=TodoItem, status_code=201)
def create_todo(merchandise: CreateTodoItem):
"""Create a brand new to-do merchandise."""
new_id = max(todos_db.keys()) + 1
new_todo = TodoItem(id=new_id, description=merchandise.description)
todos_db[new_id] = new_todo
return new_todo
@app.put("/todos/{todo_id}", response_model=TodoItem)
def update_todo(todo_id: int, merchandise: UpdateTodoItem):
"""Replace an present to-do merchandise."""
if todo_id not in todos_db:
increase HTTPException(status_code=404, element="To-do merchandise not discovered")
stored_item = todos_db[todo_id]
update_data = merchandise.dict(exclude_unset=True)
updated_item = stored_item.copy(replace=update_data)
todos_db[todo_id] = updated_item
return updated_item
@app.delete("/todos/{todo_id}", status_code=204)
def delete_todo(todo_id: int):
"""Delete a to-do merchandise by its ID."""
if todo_id not in todos_db:
increase HTTPException(status_code=404, element="To-do merchandise not discovered")
del todos_db[todo_id]
return
# --- Code to run the Uvicorn server ---
# It is a wrapper operate to run the server in a separate thread
def run_app():
uvicorn.run(app, host="0.0.0.0", port=8000)
# Apply the nest_asyncio patch
nest_asyncio.apply()
# Begin the server in a brand new thread
# The daemon=True flag means the thread will exit when the principle program exits.
thread = threading.Thread(goal=run_app, daemon=True)
thread.begin()
print("FastAPI server is operating within the background.")
print("Entry the API docs at http://127.0.0.1:8000/docs")
It is a important improve! We added:
Pydantic Fashions. We outlined the TodoItem, CreateTodoItem, and UpdateTodoItem courses, which inherit from BaseModel. FastAPI makes use of these for:
- Knowledge Validation. If a POST request is lacking an outline, FastAPI robotically sends again a 422 Unprocessable Entity error with a transparent message.
- Knowledge Serialisation. The response_model parameter within the decorators ensures the output matches the desired mannequin, which is nice for consistency and safety.
- Path Parameters. The get_todo and update_todo capabilities use a {todo_id} path parameter to determine a particular useful resource.
- Request Physique. The create_todo and update_todo capabilities count on a JSON physique that matches their respective Pydantic fashions. FastAPI parses, validates, and converts this right into a Python object for you.
- Error Dealing with. We use HTTPException to return correct HTTP error codes and messages, like a 404 Not Discovered.
Now you can take a look at the GET endpoints in your browser. To retrieve a listing of all TODO objects, kind http://127.0.0.1:8000/todos into your browser. You must see one thing like this.

Click on the Fairly-print checkbox to see the textual content specified by correct JSON format.
Likewise, to retrieve a specific ID, say ID = 3, kind the next URL into your browser: http://127.0.0.1:8000/todos/3.
For POST, PUT, and DELETE operations, it’s time to make use of certainly one of FastAPI’s greatest options.
Leverage Your Dwell Documentation
One in every of FastAPI’s nicest options is its automated, interactive API documentation. You get it totally free, simply by writing common Python code.
Together with your server operating, navigate to http://127.0.0.1:8000/docs. You’ll see the Swagger UI, which has parsed your code and generated a whole interface to your API. That is what my web page regarded like,

Utilizing this web page, you possibly can:
- View all of your endpoints, together with their HTTP strategies and corresponding docstrings.
- Examine the precise information fashions (schemas) required for requests and responses.
- Work together together with your API straight. For instance, in case you develop the POST /todos endpoint, click on “Attempt it out,” enter a JSON physique like {“description”: “Study FastAPI”}, and click on “Execute.” You’ve simply added a brand new merchandise to your checklist!
FastAPI additionally offers an alternate documentation type obtainable at http://127.0.0.1:8000/redoc. This automated, always-in-sync documentation drastically hastens growth, testing, and collaboration.
For example of utilizing the Swagger UI, let’s say we need to delete merchandise 8 — no, I didn’t actually climb Mt Everest! Click on on the DELETE button on the Swagger UI web page. Fill within the ID quantity, setting it to eight. Your web page ought to seem like this.

From right here, you possibly can both click on the Execute button or use the curl expression that’s supplied. The report comparable to ID=8 will probably be deleted out of your “database”. You possibly can test every little thing labored okay by re-retrieving all of the todos.
Implement Don’t Repeat Your self (DRY) with Dependencies
As your API grows, you’ll end up repeating logic. Maybe you could confirm API keys, set up database connections, or parse customary question parameters for pagination. FastAPI’s Dependency Injection system is a chic answer to this.
A dependency is only a operate that FastAPI runs earlier than your path operation operate. Let’s create a dependency to deal with customary question parameters for filtering our to-do checklist.
# --- Dependency ---
# Set the max variety of information to retrieve
# Additionally solely retrieve information marked as Accomplished
async def common_query_params(accomplished: Optionally available[bool] = None, skip: int = 0, restrict: int = 10):
return {"accomplished": accomplished, "skip": skip, "restrict": restrict}
This operate defines a couple of non-compulsory question parameters to restrict the quantity and standing of the todos we’ll retrieve. Now, we will “rely” on it in our path operate. Let’s modify get_all_todos to make use of it:
# Add this import on the prime
from fastapi import Relies upon
...
@app.get("/todos", response_model=Checklist[TodoItem])
def get_all_todos(params: dict = Relies upon(common_query_params)):
"""
Get all to-do objects, with non-compulsory filtering by completion standing and pagination.
"""
objects = checklist(todos_db.values())
if params["completed"] shouldn't be None:
objects = [item for item in items if item.completed == params["completed"]]
return objects[params["skip"]:params["skip"] + params["limit"]]
...
...
Now, FastAPI will:
- See that get_all_todos relies on common_query_params.
- Name common_query_params first, passing in any matching question parameters from the URL (e.g., /todos?accomplished=true&restrict=3).
- Take the return worth of the dependency ({“accomplished”: True, …}) and move it to your path operate because the params argument.
Dependencies are a robust characteristic that helps you write cleaner, extra modular, and extra reusable code. You need to use them for authentication, database periods, and lots of different functions.
To do that out, click on once more on the Swagger UI, then click on the GET button for all todos. Fill within the varieties as proven under.

Now, while you execute this (or use the given curl command), you must solely see a most of three information the place the finished standing of every todo is about to True. And that’s exactly what we get.
[
{
"id": 2,
"description": "Walk the dog",
"completed": true
},
{
"id": 4,
"description": "Take out the trash",
"completed": true
},
{
"id": 6,
"description": "Play Golf",
"completed": true
}
]
Abstract
You’ve now seen a complete overview of what makes FastAPI a compelling selection for API growth.
On this information, you discovered tips on how to:
- Set up FastAPI with its really useful toolset.
- Construct a practical API with information validation, path parameters, and request our bodies.
- Utilise the automated interactive documentation for testing and exploration.
- Preserve your code clear and reusable with FastAPI’s highly effective Dependency Injection system.
FastAPI’s fashionable design, glorious efficiency, and concentrate on developer expertise make it an excellent selection for any new Python API challenge. The automated validation and documentation options alone can save numerous hours, permitting you to concentrate on constructing options moderately than writing boilerplate code.
I’ve solely scratched the floor of the FastAPI library and its capabilities. For extra data, take a look at the FastAPI GitHub web page at:

