FastAPI Introduction
What is FastAPI?
FastAPI is a modern, high-performance web framework for building APIs with Python 3.7+ based on standard Python type hints. It was created by Sebastián Ramírez and first released in 2018. FastAPI has quickly become one of the most popular Python frameworks for API development due to its speed, ease of use, and robust feature set.
The framework was designed to be easy to use while providing high performance, automatic documentation, and strong type checking through Python's type hints system.
Why Choose FastAPI?
FastAPI offers numerous advantages that make it stand out among Python web frameworks:
- Fast: As the name suggests, it's one of the fastest Python frameworks available, on par with NodeJS and Go.
- Easy to Learn: Intuitive design makes it approachable for beginners.
- Type Checking: Leverages Python's type hints to validate data and automate documentation.
- Automatic Documentation: Generates interactive API documentation (using Swagger UI and ReDoc) automatically.
- Based on Standards: Built on open standards like OpenAPI and JSON Schema.
- Production Ready: Includes security, validation, and dependency injection features.
Prerequisites
Before diving into FastAPI, you should have:
- Python 3.7 or newer installed
- Basic understanding of Python programming
- Familiarity with HTTP requests and REST APIs (helpful but not required)
Installation
Let's start by installing FastAPI and an ASGI server called Uvicorn to run our application:
pip install fastapi uvicorn
FastAPI requires an ASGI server like Uvicorn to run. ASGI (Asynchronous Server Gateway Interface) allows asynchronous Python web servers to communicate with your application.
Your First FastAPI Application
Let's create a simple "Hello World" API to understand the basics. Create a new file named main.py
:
from fastapi import FastAPI
# Create an instance of the FastAPI class
app = FastAPI()
# Define a route with a path operation decorator
@app.get("/")
def read_root():
return {"message": "Hello World"}
To run this application, use the following command in your terminal:
uvicorn main:app --reload
Let's break down this command:
main
: the name of your Python file (main.py)app
: the FastAPI instance inside that file--reload
: automatically reloads the server when code changes (useful during development)
After running this command, your API will be available at http://127.0.0.1:8000
. If you visit this URL in your browser, you'll see:
{"message": "Hello World"}
Automatic API Documentation
One of FastAPI's most powerful features is automatic interactive API documentation. Visit:
http://127.0.0.1:8000/docs
- Swagger UI documentationhttp://127.0.0.1:8000/redoc
- ReDoc documentation
These pages are generated automatically from your code and allow you to explore and test your API endpoints directly from the browser.
Path Parameters
You can define path parameters in your routes using function parameters with type annotations:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"message": "Hello World"}
@app.get("/items/{item_id}")
def read_item(item_id: int):
return {"item_id": item_id}
In this example:
- We've added a new route
/items/{item_id}
whereitem_id
is a path parameter - The parameter is typed as
int
, so FastAPI will convert the string from the URL to an integer - If someone tries to access
/items/abc
, FastAPI will return an error since "abc" cannot be converted to an integer
Query Parameters
Query parameters are automatically extracted from function parameters that aren't declared in the path:
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/")
def read_items(skip: int = 0, limit: int = 10):
return {"skip": skip, "limit": limit}
This endpoint can be accessed like:
http://127.0.0.1:8000/items/
(will use default values: skip=0, limit=10)http://127.0.0.1:8000/items/?skip=20
(will use skip=20, limit=10)http://127.0.0.1:8000/items/?skip=20&limit=50
(will use skip=20, limit=50)
Request Body
For POST, PUT, and other methods that need to receive data, you can define the request body using Pydantic models:
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
app = FastAPI()
@app.post("/items/")
def create_item(item: Item):
item_dict = item.dict()
if item.tax:
total_price = item.price + item.tax
item_dict.update({"total_price": total_price})
return item_dict
To test this endpoint, you can use the interactive documentation at /docs
or send a POST request with JSON data:
curl -X 'POST' \
'http://127.0.0.1:8000/items/' \
-H 'Content-Type: application/json' \
-d '{
"name": "Laptop",
"description": "A high-performance laptop",
"price": 999.99,
"tax": 150
}'
The response will be:
{
"name": "Laptop",
"description": "A high-performance laptop",
"price": 999.99,
"tax": 150,
"total_price": 1149.99
}
Real-World Example: Todo API
Let's create a simple Todo API to demonstrate FastAPI in a more practical context:
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List, Optional
import uuid
app = FastAPI(title="Todo API")
# Pydantic model for a Todo item
class TodoCreate(BaseModel):
title: str
description: Optional[str] = None
completed: bool = False
class Todo(TodoCreate):
id: str
# In-memory database (in a real app, you'd use a proper database)
todos = {}
@app.post("/todos/", response_model=Todo)
def create_todo(todo: TodoCreate):
# Generate a unique ID
todo_id = str(uuid.uuid4())
# Create Todo object with ID
todo_obj = Todo(id=todo_id, **todo.dict())
# Store in our "database"
todos[todo_id] = todo_obj
return todo_obj
@app.get("/todos/", response_model=List[Todo])
def read_todos(skip: int = 0, limit: int = 10):
return list(todos.values())[skip:skip+limit]
@app.get("/todos/{todo_id}", response_model=Todo)
def read_todo(todo_id: str):
if todo_id not in todos:
raise HTTPException(status_code=404, detail="Todo not found")
return todos[todo_id]
@app.put("/todos/{todo_id}", response_model=Todo)
def update_todo(todo_id: str, todo: TodoCreate):
if todo_id not in todos:
raise HTTPException(status_code=404, detail="Todo not found")
updated_todo = Todo(id=todo_id, **todo.dict())
todos[todo_id] = updated_todo
return updated_todo
@app.delete("/todos/{todo_id}", response_model=Todo)
def delete_todo(todo_id: str):
if todo_id not in todos:
raise HTTPException(status_code=404, detail="Todo not found")
todo = todos[todo_id]
del todos[todo_id]
return todo
This API implements the basic CRUD operations (Create, Read, Update, Delete) for a Todo application. It uses:
- Pydantic models for request/response validation
- Path and query parameters
- HTTP methods (GET, POST, PUT, DELETE)
- Response models to validate and filter response data
- Error handling with HTTPException
Summary
In this introduction, we've covered the fundamentals of FastAPI:
- What FastAPI is and why it's beneficial
- Setting up a basic FastAPI application
- Creating endpoints using path decorators
- Working with path and query parameters
- Handling request bodies with Pydantic models
- Creating a real-world Todo API
FastAPI's combination of simplicity, performance, and modern features makes it an excellent choice for building APIs in Python. Its automatic documentation, data validation, and type checking help developers create robust and well-documented APIs with less code.
Additional Resources
- FastAPI Official Documentation
- Interactive FastAPI Tutorial
- Pydantic Documentation
- Uvicorn Documentation
Exercises
- Extend the Todo API to include a "priority" field (high, medium, low)
- Add an endpoint to filter todos by completion status
- Create a new API for a different domain (e.g., a simple blog with posts and comments)
- Add authentication to your API using FastAPI's security features
- Connect your API to a database like SQLite or PostgreSQL using SQLAlchemy
Happy coding with FastAPI!
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)