Getting Started#
This guide walks from zero to a working CRUD API with FastAPI-Restly.
Requirements: Python 3.10 or later.
1. Install#
From the repository root:
uv sync
If you want example project dependencies too:
make install-dev
2. Create an App#
Create main.py:
import fastapi_restly as fr
from fastapi import FastAPI
from sqlalchemy import create_engine
from sqlalchemy.orm import Mapped
fr.configure(async_database_url="sqlite+aiosqlite:///app.db")
# Create tables — for dev/SQLite only; use Alembic migrations in production
fr.DataclassBase.metadata.create_all(create_engine("sqlite:///app.db"))
app = FastAPI()
class User(fr.IDBase):
name: Mapped[str]
email: Mapped[str]
@fr.include_view(app)
class UserView(fr.AsyncRestView):
prefix = "/users"
model = User
A few things to note:
The table name is derived automatically from the class name (
User→usertable).fr.DataclassBaseis the explicit dataclass-oriented declarative base.fr.IDBaseis the convenience alias that combinesDataclassBasewith an auto-incrementing integeridprimary key.If you prefer standard SQLAlchemy declarative style (without dataclass semantics), use
fr.PlainIDBaseinstead — both work with the rest of the framework.With no manual schema, FastAPI-Restly auto-generates one from your model.
When auto-generated schemas are a good fit:
Internal tools and backoffice APIs
Early project scaffolding or prototypes
Straightforward models with minimal validation rules
3. Run#
uv run fastapi dev main.py
Note:
fastapi devrequires thefastapi[standard]extras (pip install "fastapi[standard]"or add it to your dependencies). It is not needed for production — only for the development server.
Open:
http://127.0.0.1:8000/docshttp://127.0.0.1:8000/openapi.json
4. Use the Generated Endpoints#
For prefix = "/users", generated endpoints are:
GET /users/POST /users/GET /users/{id}PATCH /users/{id}DELETE /users/{id}
Update semantics are PATCH (partial update).
You can filter results using query parameters. For example, GET /users/?filter[name]=Jane returns only users named Jane (V1 syntax; see How-To: Filter, Sort, and Paginate Lists for the full V1 and V2 syntax reference).
5. Add an Explicit Schema (Optional)#
Replace the UserView definition from Section 2 with:
class UserSchema(fr.IDSchema):
name: str
email: str
@fr.include_view(app)
class UserView(fr.AsyncRestView):
prefix = "/users"
model = User
schema = UserSchema
fr.IDSchema already includes the id field as fr.ReadOnly (excluded from create/update requests, present in responses). You can apply the same marker to your own fields: fr.ReadOnly[str] keeps a field out of write operations. fr.WriteOnly[T] does the opposite — accepted on input, omitted from responses (useful for passwords).
Choose explicit schemas when you need:
Public API contracts you want to keep stable
Custom validation logic
Field aliases and strict response shaping
Extra clarity for teams that prefer less implicit behavior
6. Test Quickly#
from fastapi.testclient import TestClient
from main import app
with TestClient(app) as client:
res = client.post("/users/", json={"name": "Jane", "email": "jane@example.com"})
assert res.status_code == 201
For test isolation (rolling back test data between tests), see the Testing guide.