RestAPI app using FastAPI
Creating REST API applications using FastAPI involves setting up endpoints to handle various HTTP requests (GET, POST, PUT, DELETE, etc.), managing data with databases, handling authentication, and providing API documentation. FastAPI simplifies this process with its declarative approach and automatic generation of documentation and validation.
Below, I'll guide you through building a basic REST API application with FastAPI. We'll create a simple to-do list API that allows you to add, read, update, and delete tasks.
Step-by-Step Guide to Creating a REST API with FastAPI
1. Installation
First, install FastAPI and Uvicorn:
pip install fastapi uvicorn
2. Setting Up Your Project Structure
Organize your project with the following structure:
my_fastapi_app/
│
├── main.py # Entry point for the application
├── models.py # Data models
├── schemas.py # Pydantic models for request/response validation
├── crud.py # CRUD operations
├── database.py # Database configuration
└── __init__.py # Package initialization
3. Creating the FastAPI App
Start with the main.py
file. This is where you initialize your FastAPI application and define the routes.
main.py:
from fastapi import FastAPI, Depends, HTTPException
from sqlalchemy.orm import Session
from typing import List
from . import models, schemas, crud
from .database import SessionLocal, engine
# Create the database tables
models.Base.metadata.create_all(bind=engine)
app = FastAPI()
# Dependency to get the DB session
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
@app.get("/")
def read_root():
return {"message": "Welcome to the ToDo API"}
# Read tasks
@app.get("/tasks/", response_model=List[schemas.Task])
def read_tasks(skip: int = 0, limit: int = 10, db: Session = Depends(get_db)):
tasks = crud.get_tasks(db, skip=skip, limit=limit)
return tasks
# Create a task
@app.post("/tasks/", response_model=schemas.Task)
def create_task(task: schemas.TaskCreate, db: Session = Depends(get_db)):
return crud.create_task(db=db, task=task)
# Read a single task by ID
@app.get("/tasks/{task_id}", response_model=schemas.Task)
def read_task(task_id: int, db: Session = Depends(get_db)):
db_task = crud.get_task(db, task_id=task_id)
if db_task is None:
raise HTTPException(status_code=404, detail="Task not found")
return db_task
# Update a task
@app.put("/tasks/{task_id}", response_model=schemas.Task)
def update_task(task_id: int, task: schemas.TaskUpdate, db: Session = Depends(get_db)):
return crud.update_task(db=db, task_id=task_id, task=task)
# Delete a task
@app.delete("/tasks/{task_id}", response_model=schemas.Task)
def delete_task(task_id: int, db: Session = Depends(get_db)):
return crud.delete_task(db=db, task_id=task_id)
4. Defining Data Models with SQLAlchemy
models.py:
from sqlalchemy import Column, Integer, String, Boolean
from .database import Base
class Task(Base):
__tablename__ = "tasks"
id = Column(Integer, primary_key=True, index=True)
title = Column(String, index=True)
description = Column(String, index=True)
completed = Column(Boolean, default=False)
5. Creating Pydantic Schemas for Data Validation
schemas.py:
from pydantic import BaseModel
class TaskBase(BaseModel):
title: str
description: str | None = None
completed: bool = False
class TaskCreate(TaskBase):
pass
class TaskUpdate(TaskBase):
pass
class Task(TaskBase):
id: int
class Config:
orm_mode = True
6. Implementing CRUD Operations
crud.py:
from sqlalchemy.orm import Session
from . import models, schemas
def get_tasks(db: Session, skip: int = 0, limit: int = 10):
return db.query(models.Task).offset(skip).limit(limit).all()
def get_task(db: Session, task_id: int):
return db.query(models.Task).filter(models.Task.id == task_id).first()
def create_task(db: Session, task: schemas.TaskCreate):
db_task = models.Task(**task.dict())
db.add(db_task)
db.commit()
db.refresh(db_task)
return db_task
def update_task(db: Session, task_id: int, task: schemas.TaskUpdate):
db_task = db.query(models.Task).filter(models.Task.id == task_id).first()
if db_task:
for key, value in task.dict().items():
setattr(db_task, key, value)
db.commit()
db.refresh(db_task)
return db_task
return None
def delete_task(db: Session, task_id: int):
db_task = db.query(models.Task).filter(models.Task.id == task_id).first()
if db_task:
db.delete(db_task)
db.commit()
return db_task
return None
7. Setting Up the Database
database.py:
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False})
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
8. Running the Application
With everything set up, you can now run your FastAPI application using Uvicorn:
uvicorn main:app --reload
This will start the server on http://localhost:8000
with auto-reload enabled, meaning it will restart whenever you make changes to the code.
9. Testing Your API
You can interact with your API using tools like curl
, Postman
, or by navigating to the interactive API documentation provided by FastAPI at http://localhost:8000/docs
.
For example, to create a new task, you can send a POST request to /tasks/
with JSON data for the task:
{
"title": "Write FastAPI Guide",
"description": "Create a comprehensive guide for FastAPI.",
"completed": false
}
Or, to get the list of tasks, send a GET request to /tasks/
.
Conclusion
By following these steps, you've built a basic REST API with FastAPI. This example can be extended and customized to fit more complex requirements, including advanced database operations, user authentication, background tasks, and more. FastAPI's ease of use and powerful features make it an excellent choice for developing modern APIs.