Tiferet OpenAPI — A Shared OpenAPI Abstraction Layer for the Tiferet Framework
Introduction
Tiferet OpenAPI provides the shared abstraction layer that both tiferet-flask and tiferet-fast depend on for OpenAPI-style API development. It extracts the common domain objects, service interfaces, domain events, mappers, YAML-backed repository, and context classes that were previously duplicated across both framework adapters.
By unifying these components into a single package, tiferet-openapi eliminates code duplication, ensures behavioral consistency between Flask and FastAPI adapters, and provides a clean foundation for building new framework adapters.
Installation
From PyPI
pip install tiferet-openapi
For Development
git clone https://github.com/greatstrength/tiferet-openapi.git
cd tiferet-openapi
python3.10 -m venv .venv
source .venv/bin/activate
pip install -e ".[test]"
Architecture
Tiferet OpenAPI follows the Tiferet framework's layered Domain-Driven Design architecture:
tiferet_openapi/
├── __init__.py — Version and public exports
├── domain/ — ApiRoute, ApiRouter (DomainObject, Pydantic v2)
├── interfaces/ — OpenApiService (Service ABC)
├── events/ — GetRouters, GetRoute, GetStatusCode (DomainEvent)
├── mappers/ — Aggregates and TransferObjects for YAML round-trip
├── repos/ — OpenApiYamlRepository (YamlLoader-backed OpenApiService)
├── contexts/ — OpenApiSessionContext (AppSessionContext), OpenApiRequestContext
└── blueprints/ — build_openapi_session_context, create_openapi_request_context
Domain Objects
ApiRoute and ApiRouter are read-only Pydantic v2 domain models that represent API routing configuration:
ApiRoute— An individual route withid,endpoint(format:router_name.route_id),path,methods, andstatus_code.ApiRouter— A named group of routes with an optional URLprefix.
Service Interface
OpenApiService is the abstract contract for API configuration access:
get_routers()— Retrieve all configured routers.get_route(route_id, router_name=None)— Look up a single route.get_status_code(error_code)— Map an error code to an HTTP status code.
Domain Events
Three domain events encapsulate the service operations for use in the feature workflow:
GetRouters— Retrieves all routers via the injectedOpenApiService.GetRoute— Parses a dotted endpoint string (e.g.,calc.add) and retrieves the matching route.GetStatusCode— Looks up the HTTP status code for a given error code.
Mappers
Aggregates and TransferObjects bridge YAML configuration and runtime domain objects:
ApiRouteAggregate,ApiRouterAggregate— Mutable aggregates with route management methods.ApiRouteYamlObject,ApiRouterYamlObject— YAML serialization with_ROLES-based role control,map()for aggregate construction,from_model()for reverse mapping.
Repository
OpenApiYamlRepository is the YAML-backed implementation of OpenApiService. It accepts a parameterized root_key (defaults to "openapi") enabling compatibility with multiple YAML formats:
root_key="openapi"— unifiedopenapi.ymlformatroot_key="flask"— legacyflask.ymlformatroot_key="fast"— legacyfast.ymlformat
Contexts
OpenApiSessionContext(AppSessionContext)— Shared session hub with injected route, status-code, and router handler callables. Provideshandle_error(HTTP status onTiferetAPIError),build_response(returning(response, status_code)tuples),generate_spec, andget_docs_spec.create_docs_handleris a deprecated alias ofget_docs_spec.OpenApiRequestContext(RequestContext)— Pydantic-aware request context that serializesBaseModelresults viamodel_dump(), with support for lists, dicts,None, and primitives.build_openapi_session_context— Composition helper that wires the hub from a resolved app session and cache.
YAML Configuration Format
The repository reads configuration from a YAML file with the following structure:
openapi: # root_key (can be 'flask', 'fast', or any custom key)
routers:
calc:
prefix: /calc
routes:
add:
path: /add
methods:
- POST
status_code: 200
subtract:
path: /subtract
methods:
- POST
status_code: 200
health:
routes:
ping:
path: /ping
methods:
- GET
status_code: 200
errors:
INVALID_INPUT: 400
DIVISION_BY_ZERO: 422
NOT_FOUND: 404
Usage
Tiferet OpenAPI is consumed by framework-specific adapters. Here's how the shared components integrate:
In tiferet-flask / tiferet-fast
Framework adapters compose OpenApiSessionContext via build_openapi_session_context and use OpenApiYamlRepository as their configuration backend:
from tiferet_openapi import (
OpenApiSessionContext,
OpenApiRequestContext,
build_openapi_session_context,
)
# Framework adapter context (e.g., FlaskApiContext)
class FlaskApiContext(OpenApiSessionContext):
# Inherits handle_error, build_response, generate_spec, get_docs_spec
pass
Direct Repository Usage
from tiferet_openapi import OpenApiYamlRepository
# Load configuration
repo = OpenApiYamlRepository(
openapi_yaml_file='app/configs/openapi.yml',
root_key='openapi',
)
# Retrieve all routers
routers = repo.get_routers()
for router in routers:
print(f"{router.name}: {router.prefix}")
for route in router.routes:
print(f" {route.endpoint} -> {route.path} [{', '.join(route.methods)}]")
# Look up a specific route
route = repo.get_route('add', router_name='calc')
print(f"Route: {route.endpoint}, Status: {route.status_code}")
# Map error code to HTTP status
status = repo.get_status_code('INVALID_INPUT') # Returns 400
status = repo.get_status_code('UNKNOWN') # Returns 500 (default)
Testing
Run the test suite:
pytest tiferet_openapi/ -v
Tests are co-located in <package>/tests/ directories:
- Domain/mapper tests use direct Pydantic constructors.
- Event tests use
DomainEvent.handle()with mockedOpenApiService. - Repo tests are integration tests using
tmp_pathwith real YAML files. - Context tests inject mock handler callables for route, status-code, and router lookup.
License
MIT — see LICENSE for details.
Metadata
Release files for tiferet-openapi 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| tiferet_openapi-1.0.0.tar.gz | 16.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tiferet_openapi-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 36.3 kB
Release files / tiferet_openapi-1.0.0.tar.gz
| Download URL | tiferet_openapi-1.0.0.tar.gz |
|---|---|
| Size | 16.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f9480e71011969c2bf4dcf1a5472ecdd7079b992d16a601429474e909b583c1c
|
|
BLAKE2b-256 checksum How to use checksums |
ea1967d5a1944b1d9631fb5e03c4bec0d82be6be610ce778d149a99769e567af
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 17, 2026.
Transparency logRelease files / tiferet_openapi-1.0.0-py3-none-any.whl
| Download URL | tiferet_openapi-1.0.0-py3-none-any.whl |
|---|---|
| Size | 19.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5c264b23bb4dfd484bfccb30958cb0b3ebf9fda1aef63305655b0c509b30a451
|
|
BLAKE2b-256 checksum How to use checksums |
a84af3c84f528972ed8d35573751776c12e9c2bf73b898e3f702bce7bb2d10ef
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 17, 2026.
Transparency log