Skip to main content

Schema-driven REST API simulation with FastAPI, Pydantic, and Polyfactory

Project description

Semblance

PyPI Python 3.10+ Ruff License: MIT

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

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

semblance-0.2.0.tar.gz (28.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

semblance-0.2.0-py3-none-any.whl (19.3 kB view details)

Uploaded Python 3

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

Hashes for semblance-0.2.0.tar.gz
Algorithm Hash digest
SHA256 7381ca59343fa9c6bfd07f78cc6631f823e94a9d93cf52ec5e6957cf34a6ce71
MD5 f4adbc315a4a30d689f2993b639517dc
BLAKE2b-256 67ccfd499264d27f92d63fb7a139463167f5c4b0e798625ea743d402c210d9eb

See more details on using hashes here.

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

Hashes for semblance-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6615e6c5b644ebb5e8a2e9c06f293746304f90544a6dd22b86f796dccf9ddc06
MD5 af607772fd3a18eacc7ed90b71221da1
BLAKE2b-256 4510ed5eb030f8e34f128cfa2a83619a8a4402e07f696e0568d65026a1c2f6b3

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page