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, rate limiting, pagination, stateful mode, optional response validation
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(seed=42)
@api.get("/users", input=UserQuery, output=list[User], list_count=2)
def users():
pass
app = api.as_fastapi()
You can register PUT, PATCH, and DELETE endpoints the same way (@api.put(...), @api.patch(...), @api.delete(..., output=None) for 204).
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"
Example output (with SemblanceAPI(seed=42) and list_count=2 for reproducibility):
[
{"name": "alice", "created_at": "2024-08-21T09:22:43.516168"},
{"name": "alice", "created_at": "2024-01-10T03:05:39.176702"}
]
Responses are generated from your output model: name comes from the query, created_at is 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
# Scaffold a minimal app (app.py and optional semblance.yaml)
semblance init [-c] [--force]
# Validate routes and link bindings without starting a server (CI-friendly)
semblance validate module:attr
# Run a Semblance app (module:attr or just module when unambiguous)
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 OpenAPI + JSON fixtures per endpoint (GET, POST, PUT, PATCH, DELETE)
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
semblance run examples.put_patch_delete.app:api --port 8000
semblance run examples.stateful_crud.app:api --port 8000
semblance run examples.request_links.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) |
| put_patch_delete | PUT, PATCH, DELETE (non-stateful) |
| stateful_crud | Full stateful CRUD: GET by id, PUT, PATCH, DELETE |
| request_links | FromHeader, FromCookie |
Testing
Use the same api from Quick Start (with app = api.as_fastapi()). With the test client you get deterministic responses without starting a server:
from semblance import SemblanceAPI, test_client
# api and app from Quick Start above
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)
# data is a list of User dicts, e.g. [{"name": "testuser", "created_at": "..."}, ...]
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, POST, PUT, PATCH, DELETE 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 |
| Rate limiting | rate_limit=N — 429 when exceeded (per endpoint, sliding window) |
| Filtering | filter_by for list endpoints |
| Stateful mode | SemblanceAPI(stateful=True) — POST stores; GET (list + by-id), PUT/PATCH/DELETE by id use store |
| Response validation | SemblanceAPI(validate_responses=True) — verify output conforms to model |
| OpenAPI | summary, description, tags on endpoints |
| Property-based testing | semblance.property_testing: strategy_for_input_model(), test_endpoint() (Hypothesis) |
Competitors & Alternatives
| Feature | Semblance | fastapi-mock | Prism | json-server | Schemathesis | Mockoon |
|---|---|---|---|---|---|---|
| Mock API server | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ |
| Python / FastAPI native | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ |
| Zero endpoint logic | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ |
| Realistic example generation | ✅ | 🟡 | ✅ | ❌ | ❌ | 🟡 |
| Input→output binding | ✅ | ❌ | ❌ | ❌ | ❌ | 🟡 |
| Deterministic seeding | ✅ | ❌ | ✅ | ❌ | ✅ | 🟡 |
| Pagination helpers | ✅ | ❌ | 🟡 | ✅ | ❌ | 🟡 |
| Error simulation | ✅ | ❌ | 🟡 | ❌ | ❌ | 🟡 |
| Stateful mode | ✅ | ❌ | ❌ | ✅ | ❌ | 🟡 |
| Extensible (plugins) | ✅ | 🟡 | ❌ | ❌ | ✅ | 🟡 |
| OpenAPI schema | ✅ | ✅ | ✅ | ❌ | ✅ | 🟡 |
| CI / pytest integration | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| Property-based testing | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ |
🟡 = partial or configurable
Documentation
Full documentation: semblance.readthedocs.io
- Getting Started
- Concepts
- Input and Output Binding
- Advanced Links
- Pagination
- Simulation Options
- Stateful Mode
- CLI
- Plugins
- Request Links
- Testing
- Troubleshooting
- Cookbook
- 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.6.0.tar.gz.
File metadata
- Download URL: semblance-0.6.0.tar.gz
- Upload date:
- Size: 49.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3a52b13d555ad923b5e217dd08b6f9625201fb5d10183f9d2a39ece0d278ee3f
|
|
| MD5 |
10f93900b9faa1c05e73a41c082f3f6d
|
|
| BLAKE2b-256 |
5890bfd47b5fabe379e45b3bb3cada0c41ce701daaf9a2ab25fb1e3ea1d24440
|
File details
Details for the file semblance-0.6.0-py3-none-any.whl.
File metadata
- Download URL: semblance-0.6.0-py3-none-any.whl
- Upload date:
- Size: 33.4 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 |
95bd4d84ecb34e24da794e2d5cbadb9cafa0028ac16893ace23c4f88d3d0d919
|
|
| MD5 |
0cc17aa35682419b5145dc15bbd00162
|
|
| BLAKE2b-256 |
c576dbd4c5b8a01564483f1d834505f09a9846f27b83f6966dca37178110353f
|