Schema-driven REST API simulation with FastAPI, Pydantic, and Polyfactory
Project description
Semblance
Schema-driven REST API simulation with FastAPI, Pydantic, and Polyfactory.
Define API behavior declaratively using schemas and dependency metadata—no endpoint logic required. Semblance is built for contract testing, prototyping, frontend development, and integration testing against realistic API simulators.
Features
- Zero endpoint logic — Schemas and link metadata define responses
- FastAPI-native — Full OpenAPI, validation, async
- Deterministic — Seeded generation for reproducible tests
- Extensible — Custom link types via plugins
- Production-ready — Error simulation, latency, pagination, stateful mode
Requirements
- Python 3.10+
- FastAPI, Pydantic, Polyfactory, Uvicorn (installed with semblance)
Installation
pip install semblance
From source (development):
git clone https://github.com/eddiethedean/semblance.git
cd semblance
pip install -e ".[dev]"
Quick Start
from datetime import date, datetime
from typing import Annotated
from pydantic import BaseModel
from semblance import DateRangeFrom, FromInput, SemblanceAPI
class UserQuery(BaseModel):
name: str = "alice"
start_date: date = date(2020, 1, 1)
end_date: date = date(2025, 12, 31)
class User(BaseModel):
name: Annotated[str, FromInput("name")]
created_at: Annotated[
datetime,
DateRangeFrom("start_date", "end_date"),
]
api = SemblanceAPI()
@api.get("/users", input=UserQuery, output=list[User])
def users():
pass
app = api.as_fastapi()
Run:
semblance run app:api --port 8000
# or
uvicorn app:app --reload
Try:
curl "http://127.0.0.1:8000/users?name=alice&start_date=2024-01-01&end_date=2024-12-31"
Responses are generated from your output model: name comes from the query, created_at is random in the date range.
Use Cases
| Use Case | Description |
|---|---|
| Contract testing | Validate client behavior against a schema-accurate mock |
| Frontend development | Run a mock API for UI work without a backend |
| Prototyping | Ship realistic API shapes before implementation |
| Integration tests | Deterministic, isolated API simulators in CI |
CLI
# Run a Semblance app
semblance run app:api [--host HOST] [--port PORT] [--reload]
# Export OpenAPI schema (optionally with response examples)
semblance export openapi app:api [-o FILE] [--examples]
# Export JSON fixtures per endpoint
semblance export fixtures app:api [-o DIR]
Examples
Runnable examples in examples/:
semblance run examples.basic.app:api --port 8000
semblance run examples.pagination.app:api --port 8000
semblance run examples.nested.app:api --port 8000
semblance run examples.stateful.app:api --port 8000
semblance run examples.advanced.app:api --port 8000
semblance run examples.error_simulation.app:api --port 8000
semblance run examples.plugins.app:api --port 8000
| Example | Description |
|---|---|
| basic | Minimal GET list with FromInput, DateRangeFrom |
| pagination | PageParams, PaginatedResponse |
| nested | Nested model linking |
| stateful | POST stores items, GET returns stored list |
| advanced | WhenInput, ComputedFrom, filter_by |
| error_simulation | error_rate, error_codes |
| plugins | Custom link (FromEnv) |
Testing
from semblance import SemblanceAPI, test_client
app = api.as_fastapi()
client = test_client(app)
r = client.get("/users?name=testuser")
assert r.status_code == 200
data = r.json()
assert all(u["name"] == "testuser" for u in data)
Deterministic seeding for reproducible tests:
api = SemblanceAPI(seed=42)
# or per-endpoint: seed_from="seed" with a query param
Plugins
Register custom link types:
from semblance import register_link, SemblanceAPI
from typing import Annotated
class FromEnv:
def __init__(self, env_var: str):
self.env_var = env_var
def resolve(self, input_data, rng):
import os
return os.environ.get(self.env_var)
register_link(FromEnv)
class User(BaseModel):
name: Annotated[str, FromEnv("USER_NAME")]
API Overview
| Feature | Description |
|---|---|
| SemblanceAPI | GET and POST endpoints with input/output models |
| Links | FromInput, DateRangeFrom, WhenInput, ComputedFrom |
| Pagination | PageParams, PaginatedResponse[T] |
| Seeding | SemblanceAPI(seed=42) or seed_from="seed" |
| Error simulation | error_rate, error_codes |
| Latency | latency_ms, jitter_ms |
| Filtering | filter_by for list endpoints |
| Stateful mode | SemblanceAPI(stateful=True) — POST stores, GET returns stored |
| OpenAPI | summary, description, tags on endpoints |
Documentation
- Getting Started
- Input and Output Binding
- Advanced Links
- Pagination
- Simulation Options
- Stateful Mode
- CLI
- Plugins
- Testing
- Roadmap
- API Reference
Development
See CONTRIBUTING.md for setup and contribution guidelines.
git clone https://github.com/eddiethedean/semblance.git
cd semblance
pip install -e ".[dev]"
pytest tests/ -v
License
MIT License.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file semblance-0.2.0.tar.gz.
File metadata
- Download URL: semblance-0.2.0.tar.gz
- Upload date:
- Size: 28.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7381ca59343fa9c6bfd07f78cc6631f823e94a9d93cf52ec5e6957cf34a6ce71
|
|
| MD5 |
f4adbc315a4a30d689f2993b639517dc
|
|
| BLAKE2b-256 |
67ccfd499264d27f92d63fb7a139463167f5c4b0e798625ea743d402c210d9eb
|
File details
Details for the file semblance-0.2.0-py3-none-any.whl.
File metadata
- Download URL: semblance-0.2.0-py3-none-any.whl
- Upload date:
- Size: 19.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6615e6c5b644ebb5e8a2e9c06f293746304f90544a6dd22b86f796dccf9ddc06
|
|
| MD5 |
af607772fd3a18eacc7ed90b71221da1
|
|
| BLAKE2b-256 |
4510ed5eb030f8e34f128cfa2a83619a8a4402e07f696e0568d65026a1c2f6b3
|