A production-quality REST API for managing energy generation assets: generators, their technical parameters, and production records. Built with FastAPI, SQLAlchemy 2.0 async, and Pydantic v2.
This project is intended as a clean, runnable reference for async FastAPI patterns — dependency injection, partial updates, generic pagination, and time-series filtering in an energy-market domain context.
| Layer | Library |
|---|---|
| Framework | FastAPI 0.111+ |
| ORM | SQLAlchemy 2.0 (async, mapped_column) |
| Database | SQLite via aiosqlite (drop-in swap to PostgreSQL) |
| Validation | Pydantic v2 |
| Server | Uvicorn (ASGI) |
| Tests | pytest + pytest-asyncio + httpx |
| Lint/Format | Ruff (line-length = 100) |
fastapi-rest-api-example/
├── src/
│ ├── main.py # App factory, lifespan, CORS, health check
│ ├── models.py # SQLAlchemy 2.0 ORM models
│ ├── schemas.py # Pydantic v2 request/response schemas
│ ├── database.py # Async engine, session factory, get_db dependency
│ └── routers/
│ ├── generators.py # Generator CRUD endpoints
│ └── production.py # Production record endpoints + summary stats
├── tests/
│ └── test_api.py # Async integration tests (httpx)
├── pyproject.toml
├── Dockerfile
├── .gitignore
└── LICENSE
| Method | Path | Description |
|---|---|---|
GET |
/health |
Health check |
GET |
/api/v1/generators |
List generators (pagination + filter) |
POST |
/api/v1/generators |
Create a generator |
GET |
/api/v1/generators/{id} |
Get single generator |
PATCH |
/api/v1/generators/{id} |
Partial update |
DELETE |
/api/v1/generators/{id} |
Soft-delete (set is_active=False) |
| Method | Path | Description |
|---|---|---|
GET |
/api/v1/generators/{id}/production |
List records (date range filter) |
POST |
/api/v1/generators/{id}/production |
Create production record |
GET |
/api/v1/generators/{id}/production/summary |
Aggregated stats |
Query parameters for /api/v1/generators:
limit(int, default 20, max 100)offset(int, default 0)technology(enum:solar,wind,thermal,hydro,bess)
Query parameters for production list:
start(ISO datetime, optional)end(ISO datetime, optional)limit/offset
git clone https://github.com/anzapatab/fastapi-rest-api-example.git
cd fastapi-rest-api-example
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev]"uvicorn src.main:app --reload --host 0.0.0.0 --port 8000The database (SQLite file energy_assets.db) is created automatically on first start via the
lifespan handler.
Interactive docs: http://localhost:8000/docs
curl http://localhost:8000/health
# {"status":"ok","version":"1.0.0"}curl -X POST http://localhost:8000/api/v1/generators \
-H "Content-Type: application/json" \
-d '{
"name": "Atacama Solar PV 1",
"technology": "solar",
"capacity_mw": 150.0,
"min_output_mw": 0.0,
"ramp_rate_mw_min": 5.0,
"location": "Atacama Desert, Chile",
"commissioned_date": "2022-06-15"
}'curl "http://localhost:8000/api/v1/generators?technology=solar&limit=10&offset=0"curl -X PATCH http://localhost:8000/api/v1/generators/1 \
-H "Content-Type: application/json" \
-d '{"capacity_mw": 160.0}'curl -X POST http://localhost:8000/api/v1/generators/1/production \
-H "Content-Type: application/json" \
-d '{
"timestamp": "2024-01-15T12:00:00",
"output_mw": 120.5,
"capacity_factor": 0.803
}'curl "http://localhost:8000/api/v1/generators/1/production/summary?start=2024-01-01T00:00:00&end=2024-12-31T23:59:59"curl -X DELETE http://localhost:8000/api/v1/generators/1
# 204 No Contentpytest tests/ -vAll tests use an in-memory SQLite database isolated per test session — no cleanup required.
docker build -t fastapi-energy-api .
docker run -p 8000:8000 fastapi-energy-apiSwap DATABASE_URL in src/database.py from:
DATABASE_URL = "sqlite+aiosqlite:///./energy_assets.db"to:
DATABASE_URL = "postgresql+asyncpg://user:password@localhost:5432/energy_assets"Install asyncpg and alembic, then use alembic init to manage migrations. No other
application code needs to change — SQLAlchemy's async session interface is database-agnostic.
MIT — see LICENSE.