Skip to main content

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 with id, endpoint (format: router_name.route_id), path, methods, and status_code.
  • ApiRouter — A named group of routes with an optional URL prefix.

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 injected OpenApiService.
  • 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" — unified openapi.yml format
  • root_key="flask" — legacy flask.yml format
  • root_key="fast" — legacy fast.yml format

Contexts

  • OpenApiSessionContext(AppSessionContext) — Shared session hub with injected route, status-code, and router handler callables. Provides handle_error (HTTP status on TiferetAPIError), build_response (returning (response, status_code) tuples), generate_spec, and get_docs_spec. create_docs_handler is a deprecated alias of get_docs_spec.
  • OpenApiRequestContext(RequestContext) — Pydantic-aware request context that serializes BaseModel results via model_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 mocked OpenApiService.
  • Repo tests are integration tests using tmp_path with 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)

Source distribution for tiferet-openapi 1.0.0
File Size Uploaded
tiferet_openapi-1.0.0.tar.gz 16.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for tiferet-openapi 1.0.0
File Interpreter ABI Platform
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 log

Release 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
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page