Building a Simple CRUD API with FastAPI
Introduction
FastAPI is a modern, high-performance Python framework for building APIs. It is fast, easy to use, and scalable, making it an excellent choice for web development. In this post, we will build a CRUD API using FastAPI.
π What you'll learn:
- Setting up FastAPI
- Creating API endpoints
- Implementing CRUD operations (Create, Read, Update, Delete)
- Running and testing the API using Swagger UI
π New to FastAPI? Check out FastAPI's official documentation.
Step 1: Install Dependencies
1.1 Create a Virtual Environment
First, create a virtual environment to manage dependencies:
# Create a virtual environment
python -m venv venv
# Activate it (Linux/macOS)
source venv/bin/activate
# Activate it (Windows)
venv\Scripts\activate
π Why use a virtual environment? It helps isolate dependencies, preventing conflicts between different projects.
1.2 Install Required Packages
Now install FastAPI along with Uvicorn:
pip install fastapi uvicorn
Explanation of Packages:
- π
fastapi
β Web framework for building APIs - π
uvicorn
β ASGI (Asynchronous Server Gateway Interface) server to run FastAPI
Step 2: Create a Simple FastAPI App
2.1 Creating the FastAPI App
Create a new file main.py
and add the following code:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"message": "Welcome to FastAPI!"}
2.2 Running the API Server
Start the server using Uvicorn. The --reload flag auto-updates the server when you save code changes:
uvicorn main:app --reload
Now open http://127.0.0.1:8000 in your browser. You should see:
{"message": "Welcome to FastAPI!"}
You can also test it via Swagger UI at http://127.0.0.1:8000/docs.
Step 3: Define a Data Model
3.1 What is CRUD?
CRUD stands for Create, Read, Update, and Delete, the four basic operations performed on data. Hereβs what each operation does:
- Create: Add a new record (e.g., a new user)
- Read: Retrieve existing records (e.g., get user details)
- Update: Modify an existing record (e.g., change user email)
- Delete: Remove a record (e.g., delete a user account)
Now let's define a data model for our users.
3.2 Creating the User Schema
To handle data properly, create a schemas.py
file:
from pydantic import BaseModel, EmailStr
from typing import Optional
class UserBase(BaseModel):
name: str
email: EmailStr
class UserCreate(UserBase):
pass
class UserUpdate(BaseModel):
name: Optional[str] = None
email: Optional[EmailStr] = None
πΉ Why Pydantic?
- π‘οΈ Ensures data validation automatically
- β Returns meaningful error messages for invalid data
3.3 Example Validation Error
Sending an invalid email:
{
"name": "John Doe",
"email": "not-an-email"
}
Response:
{
"detail": [
{
"loc": ["body", "email"],
"msg": "value is not a valid email address",
"type": "value_error.email"
}
]
}
Step 4: Create CRUD Endpoints
4.1 Implementing CRUD Operations
Now, update main.py
to include CRUD operations:
from fastapi import FastAPI, HTTPException
from schemas import UserCreate, UserUpdate
app = FastAPI()
# Temporary storage (for demonstration purposes only, use a database in production)
users = []
@app.post("/users/")
def create_user(user: UserCreate):
"""Creates a new user and stores it in memory."""
user_id = len(users)
user_dict = user.model_dump()
user_dict["id"] = user_id
users.append(user_dict)
return {"message": "User created successfully", "user": user_dict}
@app.get("/users/")
def read_users():
"""Retrieves all users."""
return users
@app.get("/users/{user_id}")
def read_user(user_id: int):
"""Fetches a user by their ID. Returns 404 if the user is not found."""
if user_id >= len(users) or user_id < 0:
raise HTTPException(status_code=404, detail="User not found")
return users[user_id]
@app.put("/users/{user_id}")
def update_user(user_id: int, user: UserUpdate):
"""Updates a user's name and/or email. Returns 404 if the user is not found."""
if user_id >= len(users) or user_id < 0:
raise HTTPException(status_code=404, detail="User not found")
if user.name:
users[user_id]["name"] = user.name
if user.email:
users[user_id]["email"] = user.email
return {"message": "User updated successfully", "user": users[user_id]}
@app.delete("/users/{user_id}")
def delete_user(user_id: int):
"""Deletes a user by ID. Returns 404 if the user is not found."""
if user_id >= len(users) or user_id < 0:
raise HTTPException(status_code=404, detail="User not found")
users.pop(user_id)
return {"message": "User deleted successfully"}
πΉ Limitations:
β οΈ In-Memory Storage: Data resets on server restart (use a database like PostgreSQL for production).
π‘οΈ Security Note: Add authentication and error handling for production use.
Step 5: Test Your API
π Open http://127.0.0.1:8000/docs and test the endpoints using Swagger UI.
π API Endpoints Summary:
Method | Endpoint | Description |
---|---|---|
POST | /users/ |
Create a new user |
GET | /users/ |
Get all users |
GET | /users/{id} |
Get a specific user |
PUT | /users/{id} |
Update a user |
DELETE | /users/{id} |
Delete a user |
Project Resources
- π GitHub Repository: fastapi-crud-demo
- π Live Demo: [https://blog-data-h3tr.onrender.com/docs)
Conclusion
You have successfully built a simple CRUD API with FastAPI! π
πΉ Next steps:
- Connect to a database (PostgreSQL)
- Store sensitive data in .env files
- Implement authentication
Stay tuned for the next post! π
π Further Reading:
- π FastAPI Docs
- π Pydantic Docs
- π Uvicorn Docs
Top comments (0)