First Run Guide
First Run Guide
Congratulations on setting up the FastAPI Boilerplate! This guide will walk you through testing your installation, understanding the basics, and making your first customizations.
Verification Checklist
Before diving deeper, let's verify everything is working correctly.
1. Check All Services
Ensure all services are running:
# For Docker Compose users
docker compose ps
# Expected output:
# NAME COMMAND SERVICE STATUS
# fastapi-boilerplate-web-1 "uvicorn app.main:app…" web running
# fastapi-boilerplate-db-1 "docker-entrypoint.s…" db running
# fastapi-boilerplate-redis-1 "docker-entrypoint.s…" redis running
# fastapi-boilerplate-worker-1 "arq src.app.core.wo…" worker running2. Test API Endpoints
Visit these URLs to confirm your API is working:
API Documentation:
- Swagger UI: http://localhost:8000/docs
- ReDoc: http://localhost:8000/redoc
Health Check:
curl http://localhost:8000/services/v1/healthExpected response:
{
"status": "healthy",
"timestamp": "2024-01-01T12:00:00Z"
}3. Database Connection
Check if the database tables were created:
# For Docker Compose
docker compose exec db psql -U postgres -d myapp -c "\dt"
# You should see tables like:
# public | users | table | postgres
# public | posts | table | postgres
# public | tiers | table | postgres
# public | rate_limits | table | postgres4. Redis Connection
Test Redis connectivity:
# For Docker Compose
docker compose exec redis redis-cli ping
# Expected response: PONGInitial Setup
Before testing features, you need to create the first superuser and tier.
Creating the First Superuser
!!! warning "Prerequisites" Make sure the database and tables are created before running create_superuser. The database should be running and the API should have started at least once.
Using Docker Compose
If using Docker Compose, uncomment this section in your docker-compose.yml:
#-------- uncomment to create first superuser --------
create_superuser:
build:
context: .
dockerfile: Dockerfile
env_file:
- ./src/.env
depends_on:
- db
command: python -m src.scripts.create_first_superuser
volumes:
- ./src:/code/srcThen run:
# Start services and run create_superuser automatically
docker compose up -d
# Or run it manually
docker compose run --rm create_superuser
# Stop the create_superuser service when done
docker compose stop create_superuserFrom Scratch
If running manually, use:
# Make sure you're in the root folder
uv run python -m src.scripts.create_first_superuserCreating the First Tier
!!! warning "Prerequisites" Make sure the database and tables are created before running create_tier.
Using Docker Compose
Uncomment the create_tier service in docker-compose.yml and run:
docker compose run --rm create_tierFrom Scratch
# Make sure you're in the root folder
uv run python -m src.scripts.create_first_tierTesting Core Features
Let's test the main features of your API.
Authentication Flow
1. Login with Admin User
Use the admin credentials you set in your .env file:
curl -X POST "http://localhost:8000/services/v1/login" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "username=admin&password=your_admin_password"You should receive a response like:
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"token_type": "bearer",
"refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
}2. Create a New User
curl -X POST "http://localhost:8000/services/v1/users" \
-H "Content-Type: application/json" \
-d '{
"name": "John Doe",
"username": "johndoe",
"email": "john@example.com",
"password": "securepassword123"
}'3. Test Protected Endpoint
Use the access token from step 1:
curl -X GET "http://localhost:8000/services/v1/users/me" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN_HERE"CRUD Operations
1. Create a Post
curl -X POST "http://localhost:8000/services/v1/posts" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN_HERE" \
-d '{
"title": "My First Post",
"content": "This is the content of my first post!"
}'2. Get All Posts
curl -X GET "http://localhost:8000/services/v1/posts" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN_HERE"3. Get Posts with Pagination
curl -X GET "http://localhost:8000/services/v1/posts?page=1&items_per_page=5" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN_HERE"Background Tasks
Test the job queue system:
1. Submit a Background Task
curl -X POST "http://localhost:8000/services/v1/tasks/task?message=hello" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN_HERE"Response:
{
"id": "550e8400-e29b-41d4-a716-446655440000"
}2. Check Task Status
curl -X GET "http://localhost:8000/services/v1/tasks/task/550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN_HERE"Caching
Test the caching system:
1. Make a Cached Request
# First request (cache miss)
curl -X GET "http://localhost:8000/services/v1/users/johndoe" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN_HERE" \
-w "Time: %{time_total}s\n"
# Second request (cache hit - should be faster)
curl -X GET "http://localhost:8000/services/v1/users/johndoe" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN_HERE" \
-w "Time: %{time_total}s\n"Your First Customization
Let's create a simple custom endpoint to see how easy it is to extend the boilerplate.
1. Create a Simple Model
Create src/app/models/item.py:
from sqlalchemy import String
from sqlalchemy.orm import Mapped, mapped_column
from app.core.db.database import Base
class Item(Base):
__tablename__ = "items"
id: Mapped[int] = mapped_column("id", autoincrement=True, nullable=False, unique=True, primary_key=True, init=False)
name: Mapped[str] = mapped_column(String(100))
description: Mapped[str] = mapped_column(String(500), default="")2. Create Pydantic Schemas
Create src/app/schemas/item.py:
from pydantic import BaseModel, Field
class ItemBase(BaseModel):
name: str = Field(..., min_length=1, max_length=100)
description: str = Field("", max_length=500)
class ItemCreate(ItemBase):
pass
class ItemCreateInternal(ItemCreate):
pass
class ItemRead(ItemBase):
id: int
class ItemUpdate(BaseModel):
name: str | None = None
description: str | None = None
class ItemUpdateInternal(ItemUpdate):
pass
class ItemDelete(BaseModel):
is_deleted: bool = True3. Create CRUD Operations
Create src/app/crud/crud_items.py:
from fastcrud import FastCRUD
from app.models.item import Item
from app.schemas.item import ItemCreateInternal, ItemUpdate, ItemUpdateInternal, ItemDelete
CRUDItem = FastCRUD[Item, ItemCreateInternal, ItemUpdate, ItemUpdateInternal, ItemDelete]
crud_items = CRUDItem(Item)4. Create API Endpoints
Create src/app/services/v1/items.py:
from typing import Annotated
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from app.api.dependencies import get_current_user
from app.core.db.database import async_get_db
from app.crud.crud_items import crud_items
from app.schemas.item import ItemCreate, ItemRead, ItemUpdate
from app.schemas.user import UserRead
router = APIRouter(tags=["items"])
@router.post("/", response_model=ItemRead, status_code=201)
async def create_item(
item: ItemCreate,
db: Annotated[AsyncSession, Depends(async_get_db)],
current_user: Annotated[UserRead, Depends(get_current_user)],
):
"""Create a new item."""
db_item = await crud_items.create(db=db, object=item)
return db_item
@router.get("/{item_id}", response_model=ItemRead)
async def get_item(item_id: int, db: Annotated[AsyncSession, Depends(async_get_db)]):
"""Get an item by ID."""
db_item = await crud_items.get(db=db, id=item_id)
if not db_item:
raise HTTPException(status_code=404, detail="Item not found")
return db_item
@router.get("/", response_model=list[ItemRead])
async def get_items(db: Annotated[AsyncSession, Depends(async_get_db)], skip: int = 0, limit: int = 100):
"""Get all items."""
items = await crud_items.get_multi(db=db, offset=skip, limit=limit)
return items["data"]
@router.patch("/{item_id}", response_model=ItemRead)
async def update_item(
item_id: int,
item_update: ItemUpdate,
db: Annotated[AsyncSession, Depends(async_get_db)],
current_user: Annotated[UserRead, Depends(get_current_user)],
):
"""Update an item."""
db_item = await crud_items.get(db=db, id=item_id)
if not db_item:
raise HTTPException(status_code=404, detail="Item not found")
updated_item = await crud_items.update(db=db, object=item_update, id=item_id)
return updated_item
@router.delete("/{item_id}")
async def delete_item(
item_id: int,
db: Annotated[AsyncSession, Depends(async_get_db)],
current_user: Annotated[UserRead, Depends(get_current_user)],
):
"""Delete an item."""
db_item = await crud_items.get(db=db, id=item_id)
if not db_item:
raise HTTPException(status_code=404, detail="Item not found")
await crud_items.delete(db=db, id=item_id)
return {"message": "Item deleted successfully"}5. Register the Router
Add your new router to src/app/services/v1/__init__.py:
from fastapi import APIRouter
from app.api.v1.login import router as login_router
from app.api.v1.logout import router as logout_router
from app.api.v1.posts import router as posts_router
from app.api.v1.rate_limits import router as rate_limits_router
from app.api.v1.tasks import router as tasks_router
from app.api.v1.tiers import router as tiers_router
from app.api.v1.users import router as users_router
from app.api.v1.items import router as items_router # Add this line
router = APIRouter(prefix="/v1")
router.include_router(login_router, prefix="/login")
router.include_router(logout_router, prefix="/logout")
router.include_router(users_router, prefix="/users")
router.include_router(posts_router, prefix="/posts")
router.include_router(tasks_router, prefix="/tasks")
router.include_router(tiers_router, prefix="/tiers")
router.include_router(rate_limits_router, prefix="/rate_limits")
router.include_router(items_router, prefix="/items") # Add this line6. Create and Run Migration
Import your new model in src/app/models/__init__.py:
from .user import User
from .post import Post
from .tier import Tier
from .rate_limit import RateLimit
from .item import Item # Add this line7. Test Your New Endpoint
Restart your application and test the new endpoints:
# Create an item
curl -X POST "http://localhost:8000/services/v1/items/" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN_HERE" \
-d '{
"name": "My First Item",
"description": "This is a test item"
}'
# Get all items
curl -X GET "http://localhost:8000/services/v1/items/" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN_HERE"Debugging Common Issues
Logs and Monitoring
Check Application Logs
# For Docker Compose
docker compose logs web
# For manual installation
tail -f src/app/logs/app.logCheck Database Logs
# For Docker Compose
docker compose logs dbCheck Worker Logs
# For Docker Compose
docker compose logs workerPerformance Testing
Test API Response Times
# Test endpoint performance
curl -w "Time: %{time_total}s\n" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN_HERE" \
http://localhost:8000/services/v1/users/meTest Database Performance
# Check active connections
docker compose exec db psql -U postgres -d myapp -c "SELECT count(*) FROM pg_stat_activity;"Monitoring Dashboard
Redis Monitor
# Monitor Redis operations
docker compose exec redis redis-cli monitorDatabase Activity
# Check database activity
docker compose exec db psql -U postgres -d myapp -c "SELECT * FROM pg_stat_activity;"Next Steps
Now that you've verified everything works and created your first custom endpoint, you're ready to dive deeper:
Essential Learning
- Project Structure - Understand how the code is organized
- Database Guide - Learn about models, schemas, and CRUD operations
- Authentication - Deep dive into JWT and user management
Advanced Features
- Caching - Speed up your API with Redis caching
- Background Tasks - Process long-running tasks asynchronously
- Rate Limiting - Protect your API from abuse
Development Workflow
- Development Guide - Best practices for extending the boilerplate
- Testing - Write tests for your new features
- Production - Deploy your API to production
Getting Help
If you encounter any issues:
- Check the logs for error messages
- Verify your configuration in the
.envfile - Review the GitHub Issues for common solutions
- Search existing issues on GitHub
- Create a new issue with detailed information
Congratulations!
You've successfully:
- Verified your FastAPI Boilerplate installation
- Tested core API functionality
- Created your first custom endpoint
- Run database migrations
- Tested authentication and CRUD operations
You're now ready to build amazing APIs with FastAPI!