Quick Start
Build your first FastKit API in 5 minutes. You'll create a working Todo API with database operations, service layer, validation, and standardized responses.
Prerequisites
Before starting, make sure you have fastkit-core installed. If you haven't done that yet, check the Installation guide first.
pip install fastkit-core
New to FastAPI? No problem — this guide assumes no prior FastAPI experience. You'll learn the patterns as you go.
Step 1 — Project Setup
Create a new directory and set up your project structure:
mkdir fastkit-quickstart
cd fastkit-quickstart
python3 -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install fastkit-core
mkdir config
touch main.py models.py services.py config/database.py .env
Your project structure should look like this:
fastkit-quickstart/
├── config/
│ └── database.py
├── .env
├── main.py
├── models.py
└── services.py
Step 2 — Configure Database
We'll use SQLite for this quickstart — no extra installation needed.
Create .env
# .env
DB_DRIVER=sqlite
DB_NAME=quickstart.db
Create config/database.py
# config/database.py
import os
CONNECTIONS = {
'default': {
'driver': os.getenv('DB_DRIVER', 'sqlite'),
'database': os.getenv('DB_NAME', 'quickstart.db'),
'echo': False # Set to True to see SQL queries in console
}
}
Step 3 — Create Your Model
Create models.py with the database model and Pydantic schemas:
# models.py
from fastkit_core.database import Base, IntIdMixin, TimestampMixin
from fastkit_core.validation import BaseSchema
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy import String, Boolean
# ── Database Model ────────────────────────
class Todo(Base, IntIdMixin, TimestampMixin):
__tablename__ = 'todos'
title: Mapped[str] = mapped_column(String(200))
description: Mapped[str|None] = mapped_column(String(500), nullable=True)
completed: Mapped[bool] = mapped_column(Boolean, default=False)
# ── Pydantic Schemas ──────────────────────
class TodoCreate(BaseSchema):
title: str
description: str | None = None
class TodoUpdate(BaseSchema):
title: str | None = None
description: str | None = None
completed: bool | None = None
class TodoResponse(BaseSchema):
id: int
title: str
description: str | None
completed: bool
model_config = {"from_attributes": True}
IntIdMixin
Adds an auto-incrementing id primary key
TimestampMixin
Adds created_at and updated_at, managed automatically
BaseSchema
Pydantic base with translated error formatting built in
Step 4 — Create the Service
Create services.py with the business logic layer:
# services.py
from fastkit_core.services import BaseCrudService
from fastkit_core.database import Repository
from models import Todo, TodoCreate, TodoUpdate, TodoResponse
from sqlalchemy.orm import Session
class TodoService(BaseCrudService[Todo, TodoCreate, TodoUpdate, TodoResponse]):
def __init__(self, session: Session):
super().__init__(
Repository(Todo, session),
response_schema=TodoResponse
)
def mark_completed(self, todo_id: int) -> Todo:
"""Custom business logic — mark a todo as done."""
return self.update(todo_id, {"completed": True})
def mark_incomplete(self, todo_id: int) -> Todo:
return self.update(todo_id, {"completed": False})
BaseCrudService
Provides create, find, all, paginate, update, delete out of the box
Repository(Todo, session)
Data access layer — keeps database queries out of business logic
response_schema
Automatically serializes model instances to Pydantic schema on every return
Step 5 — Create API Endpoints
Create main.py with the full CRUD API:
# main.py
from fastapi import FastAPI, Depends
from fastkit_core.config import ConfigManager
from fastkit_core.database import init_database, get_db, get_db_manager
from fastkit_core.http import success_response, paginated_response
from sqlalchemy.orm import Session
from models import Todo, TodoCreate, TodoUpdate
from services import TodoService
app = FastAPI(title="FastKit Quickstart API")
# Init database
config = ConfigManager(modules=['database'], auto_load=True)
init_database(config)
Todo.metadata.create_all(get_db_manager().engine)
def get_service(session: Session = Depends(get_db)) -> TodoService:
return TodoService(session)
@app.post("/todos", status_code=201)
def create_todo(data: TodoCreate, svc: TodoService = Depends(get_service)):
todo = svc.create(data.model_dump())
return success_response(data=todo.model_dump(), message="Todo created")
@app.get("/todos")
def list_todos(
page: int = 1,
per_page: int = 10,
completed: bool | None = None,
svc: TodoService = Depends(get_service)
):
filters = {"completed": completed} if completed is not None else {}
todos, meta = svc.paginate(page=page, per_page=per_page, **filters)
return paginated_response(items=[t.model_dump() for t in todos], pagination=meta)
@app.get("/todos/{todo_id}")
def get_todo(todo_id: int, svc: TodoService = Depends(get_service)):
return success_response(data=svc.find_or_fail(todo_id).model_dump())
@app.put("/todos/{todo_id}")
def update_todo(todo_id: int, data: TodoUpdate, svc: TodoService = Depends(get_service)):
todo = svc.update(todo_id, data.model_dump(exclude_unset=True))
return success_response(data=todo.model_dump(), message="Todo updated")
@app.post("/todos/{todo_id}/complete")
def complete_todo(todo_id: int, svc: TodoService = Depends(get_service)):
return success_response(data=svc.mark_completed(todo_id).model_dump())
@app.delete("/todos/{todo_id}", status_code=204)
def delete_todo(todo_id: int, svc: TodoService = Depends(get_service)):
svc.delete(todo_id)
Step 6 — Run Your API
uvicorn main:app --reload
You should see:
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process
INFO: Application startup complete.
Your API is running! Visit http://127.0.0.1:8000/docs for the interactive Swagger UI.
Test Your API
# Create a todo
curl -X POST http://127.0.0.1:8000/todos \
-H "Content-Type: application/json" \
-d '{"title": "Learn FastKit Core", "description": "Complete the quickstart"}'
# List todos (with pagination)
curl http://127.0.0.1:8000/todos
# Get specific todo
curl http://127.0.0.1:8000/todos/1
# Mark as completed
curl -X POST http://127.0.0.1:8000/todos/1/complete
# Update todo
curl -X PUT http://127.0.0.1:8000/todos/1 \
-H "Content-Type: application/json" \
-d '{"title": "Master FastKit Core"}'
# Delete todo
curl -X DELETE http://127.0.0.1:8000/todos/1
import requests
BASE = "http://127.0.0.1:8000"
# Create a todo
res = requests.post(f"{BASE}/todos", json={
"title": "Learn FastKit Core",
"description": "Complete the quickstart"
})
todo = res.json()["data"]
print(f"Created: {todo['id']} — {todo['title']}")
# List todos
res = requests.get(f"{BASE}/todos")
print(f"Total: {res.json()['pagination']['total']}")
# Mark as completed
requests.post(f"{BASE}/todos/{todo['id']}/complete")
# Update
requests.put(f"{BASE}/todos/{todo['id']}", json={"title": "Master FastKit Core"})
# Delete
requests.delete(f"{BASE}/todos/{todo['id']}")
FastAPI automatically generates interactive documentation:
- Open http://127.0.0.1:8000/docs in your browser
- Click POST /todos → Try it out
- Enter the request body and click Execute
{
"title": "Learn FastKit Core",
"description": "Complete the quickstart guide"
}
What You Built
In just a few minutes, you created a production-ready API with all of these features working out of the box:
- SQLAlchemy model with mixins
- Auto ID and timestamps
- Repository pattern
- Service with full CRUD
- Custom methods
- Reusable across the app
- Pydantic schema validation
- Type-safe data handling
- Automatic error messages
- Standardized JSON format
- Pagination with metadata
- Filtering by field
Next Steps
Now that you have a working API, explore FastKit Core's features in depth:
Troubleshooting
pip install --upgrade fastkit-core
uvicorn main:app --reload --port 8001
For PostgreSQL or MySQL, make sure the driver is installed:
pip install psycopg2-binary # PostgreSQL
pip install pymysql # MySQL