with Python, most individuals speak about Django and Flask. However there’s a more recent, very speedy choice that many Python programmers are beginning to love: FastAPI.
FastAPI is constructed on trendy Python options, utilizing commonplace sort hints to offer automated information validation, serialisation, and interactive API documentation at no cost.
Selecting the right framework is determined by 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 scale back repetitive code.
So, when do you have to select FastAPI on your mission?
- You’re constructing an API-centric service. FastAPI is designed from the bottom up for this goal.
- You need your code to be your documentation. FastAPI’s automated docs are a game-changer.
- Efficiency is vital. FastAPI is among the quickest Python frameworks out there.
Whether or not you’re constructing a small microservice or a fancy backend, figuring out what FastAPI does greatest will assist you resolve if it’s best for you. You’ll get essentially the most from this text if you happen to already know the basics of Python capabilities, HTTP strategies, and JSON.
Putting in FastAPI
You possibly can set up FastAPI with simply the fundamentals, however it’s greatest to make use of the really helpful setup. This manner, 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 surroundings. This retains your mission’s dependencies separate and your system tidy. I exploit UV for this, however you should use any instrument you want. Though I often 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 suggests including a bit of additional code to deal with Jupyter’s occasion loop, since it might probably battle with FastAPI’s async options.
tom@tpr-desktop:~$ uv init fastapi
Initialized mission `fastapi` at `/dwelling/tom/fastapi`
tom@tpr-desktop:~$ cd fastapi
tom@tpr-desktop:~/fastapi$ uv venv
Utilizing CPython 3.13.0
Creating digital surroundings at: .venv
Activate with: supply .venv/bin/activate
tom@tpr-desktop:~/fastapi$ supply .venv/bin/activate
(fastapi) tom@tpr-desktop:~/fastapi$
To get the total FastAPI expertise, set up it with the [standard] extras. This contains the FastAPI command-line instrument and the Uvicorn ASGI server, which you’ll must 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. It is best to obtain a model quantity in return. Relying on while you run this code, your model quantity will seemingly differ from mine.
import fastapi
print(fastapi.__version__)
# My Output
0.129.0
We’re now able to construct some functions.
Instance 1: Howdy World
Making a primary FastAPI software takes only a few strains of code. We’ll begin with a easy “Howdy World” message for example the framework’s core mechanics. Don’t fear, our apps will grow to be 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": "Howdy, World!"}
# Use Config + Server as a substitute of uvicorn.run()
config = uvicorn.Config(app=app, host="127.0.0.1", port=8000, log_level="information")
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 surroundings, which you wouldn’t often 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() perform ought to deal with GET requests to the basis path. The perform returns a easy textual content string.
Whenever you run the code above, you need to see output much like this.
INFO: Began server course of [28755]
INFO: Ready for software startup.
INFO: Software startup full.
INFO: Uvicorn operating on http://127.0.0.1:8000 (Press CTRL+C to stop)
When you now click on on the URL within the above output, you need to see one thing like this.
Now, let’s construct one thing extra helpful.
Instance 2: A Useful To-Do Record
Actual-world APIs must handle information. Let’s broaden our code to create a easy in-memory To-Do record API that may permit full CRUD operations. This may showcase path parameters, request our bodies, and information validation.
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import Record, Elective
import uvicorn
import nest_asyncio
import threading
app = FastAPI()
# --- Pydantic Fashions for Information Validation ---
class TodoItem(BaseModel):
id: int
description: str
accomplished: bool = False
class CreateTodoItem(BaseModel):
description: str
class UpdateTodoItem(BaseModel):
description: Elective[str] = None
accomplished: Elective[bool] = None
# --- Dependency ---
async def common_query_params(accomplished: Elective[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 automotive"),
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="Choose up youngsters from College", accomplished=True),
}
@app.get("/todos", response_model=Record[TodoItem])
def get_all_todos():
"""Get all to-do gadgets."""
return record(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 perform 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:
- Information Validation. If a POST request is lacking an outline, FastAPI mechanically sends again a 422 Unprocessable Entity error with a transparent message.
- Information 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 establish a selected 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 check the GET endpoints in your browser. To retrieve an inventory of all TODO gadgets, sort http://127.0.0.1:8000/todos into your browser. It is best to 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 selected ID, say ID = 3, sort 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 Stay Documentation
Considered one of FastAPI’s nicest options is its automated, interactive API documentation. You get it at no cost, 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 on your API. That is what my web page appeared like,

Utilizing this web page, you may:
- 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 instantly. For instance, if you happen to broaden the POST /todos endpoint, click on “Strive it out,” enter a JSON physique like {“description”: “Be taught FastAPI”}, and click on “Execute.” You’ve simply added a brand new merchandise to your record!
FastAPI additionally gives an alternate documentation fashion out there at http://127.0.0.1:8000/redoc. This automated, always-in-sync documentation drastically quickens improvement, 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 appear like this.

From right here, you may both click on the Execute button or use the curl expression that’s offered. The document comparable to ID=8 shall be deleted out of your “database”. You possibly can verify 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 that you must confirm API keys, set up database connections, or parse commonplace question parameters for pagination. FastAPI’s Dependency Injection system is a sublime resolution to this.
A dependency is only a perform that FastAPI runs earlier than your path operation perform. Let’s create a dependency to deal with commonplace question parameters for filtering our to-do record.
# --- Dependency ---
# Set the max variety of information to retrieve
# Additionally solely retrieve information marked as Accomplished
async def common_query_params(accomplished: Elective[bool] = None, skip: int = 0, restrict: int = 10):
return {"accomplished": accomplished, "skip": skip, "restrict": restrict}
This perform defines a number of non-compulsory question parameters to restrict the quantity and standing of the todos we’ll retrieve. Now, we are able to “rely” on it in our path perform. 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=Record[TodoItem])
def get_all_todos(params: dict = Relies upon(common_query_params)):
"""
Get all to-do gadgets, with non-compulsory filtering by completion standing and pagination.
"""
gadgets = record(todos_db.values())
if params["completed"] just isn't None:
gadgets = [item for item in items if item.completed == params["completed"]]
return gadgets[params["skip"]:params["skip"] + params["limit"]]
...
...
Now, FastAPI will:
- See that get_all_todos is determined by 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 go it to your path perform because the params argument.
Dependencies are a strong characteristic that helps you write cleaner, extra modular, and extra reusable code. You should utilize them for authentication, database classes, 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 kinds as proven beneath.

Now, while you execute this (or use the given curl command), you need to solely see a most of three information the place the finished standing of every todo is ready 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 improvement.
On this information, you realized easy methods to:
- Set up FastAPI with its really helpful toolset.
- Construct a purposeful API with information validation, path parameters, and request our bodies.
- Utilise the automated interactive documentation for testing and exploration.
- Hold your code clear and reusable with FastAPI’s highly effective Dependency Injection system.
FastAPI’s trendy design, wonderful efficiency, and deal with developer expertise make it a really perfect selection for any new Python API mission. The automated validation and documentation options alone can save numerous hours, permitting you to deal with constructing options fairly than writing boilerplate code.
I’ve solely scratched the floor of the FastAPI library and its capabilities. For extra info, try the FastAPI GitHub web page at:
