How to Build a REST API in 10 Minutes with FastAPI (2025 Guide)
If you've been putting off building that backend API because you thought it would take days — think again. With FastAPI, you can go from zero to a fully functional REST API in under 10 minutes.
I've built dozens of APIs, and FastAPI is hands-down the fastest way to get a production-ready backend running. Here's exactly how to do it.
Why FastAPI (Not Flask or Django)?
- Automatic docs — Swagger UI and ReDoc are built-in. No extra setup.
- Type hints = validation — Pydantic handles request/response validation automatically.
- Async by default — Built on Starlette, it handles async like a champ.
- Fast performance — One of the fastest Python frameworks (comparable to Go's net/http).
Step 1: Install & Setup
mkdir my-api && cd my-api
python -m venv venv
source venv/bin/activate # or venv\Scripts\activate on Windows
pip install fastapi uvicorn
Step 2: Write the Code
Create a file called main.py:
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional, List
app = FastAPI(title="My Awesome API", version="1.0.0")
# Data model
class Item(BaseModel):
name: str
price: float
description: Optional[str] = None
in_stock: bool = True
# In-memory database (for demo)
db: List[Item] = []
@app.get("/")
async def root():
return {"message": "🚀 API is running!", "docs": "/docs"}
@app.get("/items", response_model=List[Item])
async def list_items():
return db
@app.post("/items", response_model=Item, status_code=201)
async def create_item(item: Item):
db.append(item)
return item
@app.get("/items/{item_id}")
async def get_item(item_id: int):
if item_id < len(db):
return db[item_id]
return {"error": "Item not found"}, 404
@app.delete("/items/{item_id}")
async def delete_item(item_id: int):
if item_id < len(db):
removed = db.pop(item_id)
return {"deleted": removed.name}
return {"error": "Item not found"}, 404
Step 3: Run It
uvicorn main:app --reload --port 8000
That's it. Open http://localhost:8000/docs and you'll see a beautiful, interactive API documentation page where you can test every endpoint right in your browser.
Step 4: Add Error Handling
Let's make it production-ready with proper error handling:
from fastapi import HTTPException
@app.get("/items/{item_id}")
async def get_item(item_id: int):
if item_id < 0 or item_id >= len(db):
raise HTTPException(
status_code=404,
detail=f"Item {item_id} not found"
)
return db[item_id]
Step 5: Add Query Parameters
FastAPI makes filtering effortless:
@app.get("/items")
async def list_items(
skip: int = 0,
limit: int = 10,
in_stock: Optional[bool] = None
):
items = db[skip : skip + limit]
if in_stock is not None:
items = [i for i in items if i.in_stock == in_stock]
return items
Now /items?in_stock=true&limit=5 just works. No manual parsing.
Step 6: Connect a Real Database (SQLite Example)
from databases import Database
import sqlalchemy
DATABASE_URL = "sqlite:///./test.db"
database = Database(DATABASE_URL)
metadata = sqlalchemy.MetaData()
items_table = sqlalchemy.Table(
"items", metadata,
sqlalchemy.Column("id", sqlalchemy.Integer, primary_key=True),
sqlalchemy.Column("name", sqlalchemy.String(50)),
sqlalchemy.Column("price", sqlalchemy.Float),
sqlalchemy.Column("description", sqlalchemy.String(255)),
sqlalchemy.Column("in_stock", sqlalchemy.Boolean, default=True),
)
@app.on_event("startup")
async def startup():
await database.connect()
engine = sqlalchemy.create_engine(DATABASE_URL)
metadata.create_all(engine)
@app.on_event("shutdown")
async def shutdown():
await database.disconnect()
@app.get("/items")
async def list_items():
query = items_table.select()
return await database.fetch_all(query)
Pro Tips I Wish I Knew Earlier
1. Use Depends for Clean Dependency Injection
from fastapi import Depends
async def get_db():
# Return your DB session
return database
@app.post("/items")
async def create_item(item: Item, db=Depends(get_db)):
# db is automatically injected
query = items_table.insert().values(**item.dict())
await db.execute(query)
return item
2. Environment Variables with Pydantic Settings
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
app_name: str = "My API"
database_url: str
secret_key: str
class Config:
env_file = ".env"
settings = Settings()
3. CORS for Frontend Integration
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3000"],
allow_methods=["*"],
allow_headers=["*"],
)
File Structure for a Real Project
my-api/
├── main.py
├── models.py # Pydantic models
├── database.py # DB connection
├── crud.py # CRUD operations
├── routers/
│ ├── items.py # Item endpoints
│ └── users.py # User endpoints
├── tests/
│ └── test_items.py
├── requirements.txt
└── .env
When to Use FastAPI (and When Not To)
✅ Great for:
- REST APIs and microservices
- ML model serving
- Quick MVP backends
- Webhook handlers
❌ Maybe not for:
- Full-stack apps with complex auth (consider Django)
- Simple scripts (overkill)
- Real-time WebSocket-only apps (consider aiohttp)
Benchmark: How Fast Is It Really?
In my tests with a simple GET endpoint returning JSON:
| Framework | Requests/sec |
|---|---|
| FastAPI | ~15,000 |
| Flask | ~3,000 |
| Django REST | ~1,500 |
| Express.js | ~12,000 |
Your mileage may vary depending on hardware and payload size.
Get Started Right Now
pip install fastapi uvicorn
# Copy the code above into main.py
uvicorn main:app --reload
Open http://localhost:8000/docs and start building. You'll have a working API in less time than it takes to finish your coffee.
What are you building with FastAPI? Drop a comment — I'd love to hear about your projects!
If you found this useful, follow me for more Python and backend tutorials.
Top comments (0)