REST API for users and nested orders, built with FastAPI and SQLAlchemy. The service exposes JSON over HTTP and uses an in-memory SQLite database by default (suitable for local development).
| Library | Role |
|---|---|
| FastAPI | Web framework: routing, dependency injection, OpenAPI docs |
Uvicorn (with [standard]) |
ASGI server (HTTP, WebSockets, optional HTTP/2 helpers) |
| SQLAlchemy 2.x | ORM and database access |
Pydantic (email extra) |
Request/response models and validation (including email) |
| pydantic-settings | Typed configuration from environment variables |
Optional development dependencies (install with pip install -e ".[dev]"):
| Library | Role |
|---|---|
| HTTPX | HTTP client used by FastAPI’s TestClient |
| pytest | Test runner |
- Python 3.11 or newer
pip(bundled with most Python installs)
-
Clone or copy this repository and open a terminal in the project root.
-
Create and activate a virtual environment:
python3 -m venv .venv source .venv/bin/activate # Windows: .venv\Scripts\activate
-
Install the application (editable install so code changes are picked up immediately):
pip install -e .For optional dev tools (
httpx,pytest):pip install -e ".[dev]"
Environment variables use the prefix APP_. The running process uses these for the app and database layer:
| Variable | Default | Description |
|---|---|---|
APP_TITLE |
rest-order-service |
Application title (shown in OpenAPI) |
APP_DATABASE_URL |
sqlite:// |
SQLAlchemy database URL (default is in-memory SQLite with a static pool) |
app/config.py also defines APP_HOST and APP_PORT for future use; the listen address and port are chosen on the Uvicorn command line (--host, --port).
Example:
export APP_DATABASE_URL="sqlite:////tmp/rest_order.db"Start the API with Uvicorn from the project root (with the virtual environment activated):
uvicorn app.main:app --host 0.0.0.0 --port 8080After startup:
- Interactive API docs (Swagger UI): http://127.0.0.1:8080/docs
- OpenAPI JSON: http://127.0.0.1:8080/openapi.json
Main routes:
GET/POST /api/v1/users,GET/PUT/PATCH/DELETE /api/v1/users/{user_id}GET/POST /api/v1/users/{user_id}/orders,GET/PUT/PATCH/DELETE /api/v1/users/{user_id}/orders/{order_id}
The database schema is created on application startup.
tests/unit/— Service-layer tests (user_service,order_service) using a dedicated in-memory SQLite engine per test.tests/integration/— End-to-end HTTP tests withTestClientand aget_dbdependency override so each test gets an isolated database.
Shared fixtures and helpers live in tests/conftest.py.
-
Open a terminal in the project root (the directory that contains
pyproject.toml). -
Activate the same virtual environment you use for development (see Setup if you have not created one yet):
source .venv/bin/activate # Windows: .venv\Scripts\activate
-
Install dev dependencies so
pytestandhttpx(required by FastAPI’sTestClient) are available. You can do this once, or again after changing dependencies:pip install -e ".[dev]" -
Run the full suite from the project root:
pytest
-
Optional: run only part of the suite, for example:
pytest tests/unit # service-layer tests only pytest tests/integration # HTTP API tests only pytest tests/unit/test_user_service.py -v # one file, verbose pytest -x # stop on first failure
If a command fails with pytest: command not found, the virtual environment is probably not activated or dev dependencies were not installed (repeat steps 2 and 3).
When calling the real app object (not the test overrides), use a TestClient context manager so lifespan hooks (including table creation on the app’s default engine) run:
from fastapi.testclient import TestClient
from app.main import app
with TestClient(app) as client:
response = client.get("/api/v1/users")
assert response.status_code == 200