Python FastAPI Basics
Introduction
FastAPI is a modern, fast (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 has quickly gained popularity among Python developers due to its simplicity, speed, and developer-friendly features.
FastAPI stands out from other Python web frameworks because of:
- Speed: It's one of the fastest Python frameworks available, on par with NodeJS and Go
- Easy to use: Designed to be easy to use and learn
- Less code: Minimizes code duplication, reducing bugs
- Automatic documentation: Generates interactive API documentation automatically
- Modern Python: Takes full advantage of Python 3.7+ features like type hints
In this tutorial, we'll cover the basics of FastAPI and build a simple API to understand how it works.
Prerequisites
Before we begin, make sure you have:
- Python 3.7 or later installed
- Basic understanding of Python
- Familiarity with API concepts
- A code editor of your choice
Installation
Let's start by installing FastAPI and Uvicorn, an ASGI server that we'll use to run our FastAPI application:
pip install fastapi uvicorn
Creating Your First FastAPI Application
Let's create a simple "Hello World" API:
from fastapi import FastAPI
# Create a FastAPI instance
app = FastAPI()
# Define a route
@app.get("/")
def read_root():
return {"message": "Hello, FastAPI!"}
Save this code as main.py
. To run the application, use the following command:
uvicorn main:app --reload
Breaking down this command:
main
: The name of the Python file (main.py)app
: The FastAPI instance name inside the file--reload
: Enables auto-reload when code changes
Now, open your browser and navigate to http://127.0.0.1:8000
. You should see:
{
"message": "Hello, FastAPI!"
}
Congratulations! You've created your first FastAPI application.
Path Parameters
Let's make our API more dynamic by adding path parameters:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"message": "Hello, FastAPI!"}
@app.get("/items/{item_id}")
def read_item(item_id: int):
return {"item_id": item_id}
Notice how we declared item_id
as an int
. FastAPI will:
- Convert the path parameter to the specified type
- Validate the data
- Document the parameter in the API docs
Try accessing http://127.0.0.1:8000/items/5
and you'll see:
{
"item_id": 5
}
If you try with a non-integer value like http://127.0.0.1:8000/items/abc
, FastAPI will return an error, as it expects an integer.
Query Parameters
Query parameters are specified after the ?
in a URL. FastAPI makes it easy to work with them:
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/")
def read_items(skip: int = 0, limit: int = 10):
return {"skip": skip, "limit": limit}
If you access http://127.0.0.1:8000/items/?skip=20&limit=50
, you'll see:
{
"skip": 20,
"limit": 50
}
Parameters with default values are optional. If you simply access http://127.0.0.1:8000/items/
, you'll get:
{
"skip": 0,
"limit": 10
}
Request Body
When you need to send data to the API, you can use a request body. FastAPI makes it easy to define request bodies 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:
price_with_tax = item.price + item.tax
item_dict.update({"price_with_tax": price_with_tax})
return item_dict
To test this endpoint, you can use tools like Postman, curl, or the automatically generated interactive documentation.
Automatic Documentation
One of the most powerful features of FastAPI is its automatic documentation. FastAPI automatically generates interactive API documentation based on your code.
To access the documentation, run your FastAPI application and navigate to:
- Swagger UI:
http://127.0.0.1:8000/docs
- ReDoc:
http://127.0.0.1:8000/redoc
These interfaces allow you to view your API endpoints, send requests directly from the browser, and see the expected request/response formats.
Building a Complete REST API
Now, let's put everything together to build a simple REST API for managing a collection of books:
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List, Optional
app = FastAPI(title="Book Library API")
# Pydantic model for a book
class Book(BaseModel):
id: Optional[int] = None
title: str
author: str
pages: int
published: bool = False
# In-memory database (for demonstration)
books_db = []
book_id_counter = 1
@app.post("/books/", response_model=Book, status_code=201)
def create_book(book: Book):
global book_id_counter
book.id = book_id_counter
book_id_counter += 1
books_db.append(book)
return book
@app.get("/books/", response_model=List[Book])
def read_books(skip: int = 0, limit: int = 10):
return books_db[skip: skip + limit]
@app.get("/books/{book_id}", response_model=Book)
def read_book(book_id: int):
for book in books_db:
if book.id == book_id:
return book
raise HTTPException(status_code=404, detail="Book not found")
@app.put("/books/{book_id}", response_model=Book)
def update_book(book_id: int, updated_book: Book):
for i, book in enumerate(books_db):
if book.id == book_id:
updated_book.id = book_id
books_db[i] = updated_book
return updated_book
raise HTTPException(status_code=404, detail="Book not found")
@app.delete("/books/{book_id}", status_code=204)
def delete_book(book_id: int):
for i, book in enumerate(books_db):
if book.id == book_id:
books_db.pop(i)
return
raise HTTPException(status_code=404, detail="Book not found")
This API allows you to:
- Create a new book
- Retrieve all books (with pagination)
- Retrieve a specific book by ID
- Update a book
- Delete a book
Exception Handling
In the example above, we used HTTPException
to handle errors. FastAPI provides a simple way to manage exceptions:
from fastapi import FastAPI, HTTPException
app = FastAPI()
@app.get("/items/{item_id}")
def read_item(item_id: int):
if item_id == 0:
raise HTTPException(status_code=404, detail="Item not found")
return {"item_id": item_id}
Adding Dependency Injection
FastAPI has a powerful dependency injection system that helps you create reusable components:
from fastapi import FastAPI, Depends, HTTPException
app = FastAPI()
def get_db():
db = {"key": "value"}
return db
@app.get("/items/")
def read_items(db: dict = Depends(get_db)):
return {"db": db}
When a request is made to /items/
, FastAPI will:
- Call the
get_db()
function - Pass the result to
read_items()
asdb
This is extremely useful for database connections, authentication, and other common tasks.
Summary
In this tutorial, we've covered the basics of FastAPI, including:
- Setting up a FastAPI application
- Creating API endpoints with path and query parameters
- Working with request bodies using Pydantic models
- Automatic API documentation
- Building a complete REST API
- Exception handling
- Introduction to dependency injection
FastAPI provides a modern, efficient way to build APIs with Python. Its focus on developer experience, combined with its performance and automatic documentation, makes it an excellent choice for Python web development.
Additional Resources
Here are some resources to dive deeper into FastAPI:
Practice Exercises
- Extend the book API to include features like searching by title or author
- Add a rating system to the books API
- Implement basic authentication for the API
- Create a front-end application that interacts with your FastAPI backend
- Add database integration using SQLAlchemy instead of the in-memory list
By completing these exercises, you'll gain a deeper understanding of FastAPI and be well on your way to building robust web applications with Python.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)