4 Commits
0.0.3 ... main

Author SHA1 Message Date
6bafa435f1 using doc-forge (#1)
Reviewed-on: #1
Co-authored-by: Vishesh 'ironeagle' Bangotra <aetoskia@gmail.com>
Co-committed-by: Vishesh 'ironeagle' Bangotra <aetoskia@gmail.com>
2026-01-22 11:28:32 +00:00
29c1579f40 v0.0.4 — Documents and packages OpenAPI-first application templates, adds multi-template CLI scaffolding, and enforces package-bound documentation generation.
All checks were successful
continuous-integration/drone/tag Build is passing
2026-01-11 21:44:11 +05:30
a3c063b569 docs(templates): document CRUD and model CRUD apps and expose them in mkdocs
- Add comprehensive module and function docstrings to crud_app and model_app templates
- Document OpenAPI-first guarantees, non-goals, and usage patterns in templates
- Add template-level __init__.py files with CLI and client usage examples
- Update mkdocs.yml to include CRUD and model-based CRUD template documentation
- Ensure template documentation follows strict package-bound mkdocstrings rules
2026-01-11 21:42:30 +05:30
72b5be6976 docs, cli: enforce package-bound docs, add template scaffolding, and document CLI usage
- Restrict mkdocstrings generation to real Python packages (require __init__.py)
- Add explicit documentation section for CLI scaffolding and templates
- Generalize CLI to support multiple templates with dynamic discovery
- Package templates correctly for importlib.resources access
- Add fully documented health_app template (app entry point and handlers)
- Fix setuptools package-data configuration for bundled templates

These changes make documentation import-safe, clarify package boundaries,
and provide a deterministic, OpenAPI-first scaffolding workflow via CLI.
2026-01-11 19:26:21 +05:30
68 changed files with 4712 additions and 277 deletions

1
.gitignore vendored
View File

@@ -38,3 +38,4 @@ Thumbs.db
*.swo
*~
*.tmp
site

10
docforge.nav.yml Normal file
View File

@@ -0,0 +1,10 @@
home: openapi_first/index.md
groups:
Application Bootstrap:
- openapi_first/app.md
- openapi_first/binder.md
Core Utilities:
- openapi_first/loader.md
- openapi_first/errors.md
OpenAPI Client:
- openapi_first/client.md

View File

@@ -0,0 +1,3 @@
# Data
::: openapi_first.templates.crud_app.data

View File

@@ -0,0 +1,3 @@
# Crud App
::: openapi_first.templates.crud_app

View File

@@ -0,0 +1,3 @@
# Main
::: openapi_first.templates.crud_app.main

View File

@@ -0,0 +1,3 @@
# Routes
::: openapi_first.templates.crud_app.routes

View File

@@ -0,0 +1,3 @@
# Test Crud App
::: openapi_first.templates.crud_app.test_crud_app

View File

@@ -0,0 +1,3 @@
# Health App
::: openapi_first.templates.health_app

View File

@@ -0,0 +1,3 @@
# Main
::: openapi_first.templates.health_app.main

View File

@@ -0,0 +1,3 @@
# Routes
::: openapi_first.templates.health_app.routes

View File

@@ -0,0 +1,3 @@
# Templates
::: openapi_first.templates

View File

@@ -0,0 +1,3 @@
# Data
::: openapi_first.templates.model_app.data

View File

@@ -0,0 +1,3 @@
# Model App
::: openapi_first.templates.model_app

View File

@@ -0,0 +1,3 @@
# Main
::: openapi_first.templates.model_app.main

View File

@@ -0,0 +1,3 @@
# Models
::: openapi_first.templates.model_app.models

View File

@@ -0,0 +1,3 @@
# Routes
::: openapi_first.templates.model_app.routes

View File

@@ -0,0 +1,3 @@
# Test Model App
::: openapi_first.templates.model_app.test_model_app

View File

@@ -1,159 +0,0 @@
"""
MkDocs documentation management CLI.
This script provides a proper CLI interface to:
- Generate MkDocs Markdown files with mkdocstrings directives
- Build the documentation site
- Serve the documentation site locally
All operations are performed by calling MkDocs as a Python library
(no shell command invocation).
Requirements:
- mkdocs
- mkdocs-material
- mkdocstrings[python]
Usage:
python manage_docs.py generate
python manage_docs.py build
python manage_docs.py serve
Optional flags:
--docs-dir PATH Path to docs directory (default: ./docs)
--package-root NAME Root Python package name (default: mail_intake)
"""
from __future__ import annotations
import argparse
from pathlib import Path
from mkdocs.commands import build as mkdocs_build
from mkdocs.commands import serve as mkdocs_serve
from mkdocs.config import load_config
PROJECT_ROOT = Path(__file__).resolve().parent
DEFAULT_DOCS_DIR = PROJECT_ROOT / "docs"
DEFAULT_PACKAGE_ROOT = "openapi_first"
MKDOCS_YML = PROJECT_ROOT / "mkdocs.yml"
def generate_docs_from_nav(
project_root: Path,
docs_root: Path,
package_root: str,
) -> None:
"""
Create and populate MkDocs Markdown files with mkdocstrings directives.
This function:
- Walks the Python package structure
- Mirrors it under the docs directory
- Creates missing .md files
- Creates index.md for packages (__init__.py)
- Overwrites content with ::: package.module
Examples:
mail_intake/__init__.py -> docs/mail_intake/index.md
mail_intake/config.py -> docs/mail_intake/config.md
mail_intake/adapters/__init__.py -> docs/mail_intake/adapters/index.md
mail_intake/adapters/base.py -> docs/mail_intake/adapters/base.md
"""
package_dir = project_root / package_root
if not package_dir.exists():
raise FileNotFoundError(f"Package not found: {package_dir}")
docs_root.mkdir(parents=True, exist_ok=True)
for py_file in package_dir.rglob("*.py"):
rel = py_file.relative_to(project_root)
if py_file.name == "__init__.py":
# Package → index.md
module_path = ".".join(rel.parent.parts)
md_path = docs_root / rel.parent / "index.md"
title = rel.parent.name.replace("_", " ").title()
else:
# Regular module → <module>.md
module_path = ".".join(rel.with_suffix("").parts)
md_path = docs_root / rel.with_suffix(".md")
title = md_path.stem.replace("_", " ").title()
md_path.parent.mkdir(parents=True, exist_ok=True)
content = f"""# {title}
::: {module_path}
"""
md_path.write_text(content, encoding="utf-8")
def load_mkdocs_config():
if not MKDOCS_YML.exists():
raise FileNotFoundError("mkdocs.yml not found at project root")
return load_config(str(MKDOCS_YML))
def cmd_generate(args: argparse.Namespace) -> None:
generate_docs_from_nav(
project_root=PROJECT_ROOT,
docs_root=args.docs_dir,
package_root=args.package_root,
)
def cmd_build(_: argparse.Namespace) -> None:
config = load_mkdocs_config()
mkdocs_build.build(config)
def cmd_serve(_: argparse.Namespace) -> None:
mkdocs_serve.serve(
config_file=str(MKDOCS_YML)
)
def main() -> None:
parser = argparse.ArgumentParser(
prog="manage_docs.py",
description="Manage MkDocs documentation for the project",
)
parser.add_argument(
"--docs-dir",
type=Path,
default=DEFAULT_DOCS_DIR,
help="Path to the docs directory",
)
parser.add_argument(
"--package-root",
default=DEFAULT_PACKAGE_ROOT,
help="Root Python package name",
)
subparsers = parser.add_subparsers(dest="command", required=True)
subparsers.add_parser(
"generate",
help="Generate Markdown files with mkdocstrings directives",
).set_defaults(func=cmd_generate)
subparsers.add_parser(
"build",
help="Build the MkDocs site",
).set_defaults(func=cmd_build)
subparsers.add_parser(
"serve",
help="Serve the MkDocs site locally",
).set_defaults(func=cmd_serve)
args = parser.parse_args()
args.func(args)
if __name__ == "__main__":
main()

6
mcp_docs/index.json Normal file
View File

@@ -0,0 +1,6 @@
{
"project": "openapi_first",
"type": "docforge-model",
"modules_count": 22,
"source": "docforge"
}

View File

@@ -0,0 +1,53 @@
{
"module": "openapi_first.app",
"content": {
"path": "openapi_first.app",
"docstring": "openapi_first.app\n=========================\n\nOpenAPI-first application bootstrap for FastAPI.\n\nThis module provides `OpenAPIFirstApp`, a thin but strict abstraction\nthat enforces OpenAPI as the single source of truth for a FastAPI service.\n\nCore principles\n---------------\n- The OpenAPI specification (JSON or YAML) defines the entire API surface.\n- Every operationId in the OpenAPI spec must have a corresponding\n Python handler function.\n- Handlers are plain Python callables (no FastAPI decorators).\n- FastAPI route registration is derived exclusively from the spec.\n- FastAPI's autogenerated OpenAPI schema is fully overridden.\n\nWhat this module does\n---------------------\n- Loads and validates an OpenAPI 3.x specification.\n- Dynamically binds HTTP routes to handler functions using operationId.\n- Registers routes with FastAPI at application startup.\n- Ensures runtime behavior matches the OpenAPI contract exactly.\n\nWhat this module does NOT do\n----------------------------\n- It does not generate OpenAPI specs.\n- It does not generate client code.\n- It does not introduce a new framework or lifecycle.\n- It does not alter FastAPI dependency injection semantics.\n\nIntended usage\n--------------\nThis module is intended for teams that want:\n\n- OpenAPI-first API development\n- Strong contract enforcement\n- Minimal FastAPI boilerplate\n- Predictable, CI-friendly failures for spec/implementation drift",
"objects": {
"FastAPI": {
"name": "FastAPI",
"kind": "alias",
"path": "openapi_first.app.FastAPI",
"signature": "<bound method Alias.signature of Alias('FastAPI', 'fastapi.FastAPI')>",
"docstring": null
},
"load_openapi": {
"name": "load_openapi",
"kind": "function",
"path": "openapi_first.app.load_openapi",
"signature": "<bound method Alias.signature of Alias('load_openapi', 'openapi_first.loader.load_openapi')>",
"docstring": "Load and validate an OpenAPI 3.x specification from disk.\n\nThe specification is parsed based on file extension and validated\nusing a strict OpenAPI schema validator. Any error results in an\nimmediate exception, preventing application startup.\n\nParameters\n----------\npath : str or pathlib.Path\n Filesystem path to an OpenAPI specification file.\n Supported extensions:\n - `.json`\n - `.yaml`\n - `.yml`\n\nReturns\n-------\ndict\n Parsed and validated OpenAPI specification.\n\nRaises\n------\nOpenAPISpecLoadError\n If the file does not exist, cannot be parsed, or fails\n OpenAPI schema validation."
},
"bind_routes": {
"name": "bind_routes",
"kind": "function",
"path": "openapi_first.app.bind_routes",
"signature": "<bound method Alias.signature of Alias('bind_routes', 'openapi_first.binder.bind_routes')>",
"docstring": "Bind OpenAPI operations to FastAPI routes.\n\nIterates through the OpenAPI specification paths and methods,\nresolves each operationId to a handler function, and registers\na corresponding APIRoute on the FastAPI application.\n\nParameters\n----------\napp : fastapi.FastAPI\n The FastAPI application instance to which routes will be added.\n\nspec : dict\n Parsed OpenAPI 3.x specification dictionary.\n\nroutes_module : module\n Python module containing handler functions. Each handler's\n name MUST exactly match an OpenAPI operationId.\n\nRaises\n------\nMissingOperationHandler\n If an operationId is missing from the spec or if no corresponding\n handler function exists in the routes module.\n\nBehavior guarantees\n-------------------\n- Route registration is deterministic and spec-driven.\n- No route decorators are required or supported.\n- Handler resolution errors surface at application startup."
},
"OpenAPIFirstApp": {
"name": "OpenAPIFirstApp",
"kind": "class",
"path": "openapi_first.app.OpenAPIFirstApp",
"signature": "<bound method Class.signature of Class('OpenAPIFirstApp', 49, 118)>",
"docstring": "FastAPI application enforcing OpenAPI-first design.\n\n`OpenAPIFirstApp` subclasses FastAPI and replaces manual route\nregistration with OpenAPI-driven binding. All routes are derived\nfrom the provided OpenAPI specification, and each operationId is\nmapped to a Python function in the supplied routes module.\n\nParameters\n----------\nopenapi_path : str\n Filesystem path to the OpenAPI 3.x specification file.\n This specification is treated as the authoritative API contract.\n\nroutes_module : module\n Python module containing handler functions whose names correspond\n exactly to OpenAPI operationId values.\n\n**fastapi_kwargs\n Additional keyword arguments passed directly to `fastapi.FastAPI`\n (e.g., title, version, middleware, lifespan handlers).\n\nRaises\n------\nOpenAPIFirstError\n If the OpenAPI specification is invalid, or if any declared\n operationId does not have a corresponding handler function.\n\nBehavior guarantees\n-------------------\n- No route can exist without an OpenAPI declaration.\n- No OpenAPI operation can exist without a handler.\n- Swagger UI and `/openapi.json` always reflect the provided spec.\n- Handler functions remain framework-agnostic and testable.\n\nExample\n-------\n>>> from openapi_first import OpenAPIFirstApp\n>>> import app.routes as routes\n>>>\n>>> app = OpenAPIFirstApp(\n... openapi_path=\"app/openapi.json\",\n... routes_module=routes,\n... title=\"Example Service\"\n... )",
"members": {
"openapi": {
"name": "openapi",
"kind": "attribute",
"path": "openapi_first.app.OpenAPIFirstApp.openapi",
"signature": null,
"docstring": null
}
}
},
"Any": {
"name": "Any",
"kind": "alias",
"path": "openapi_first.app.Any",
"signature": "<bound method Alias.signature of Alias('Any', 'typing.Any')>",
"docstring": null
}
}
}
}

View File

@@ -0,0 +1,51 @@
{
"module": "openapi_first.binder",
"content": {
"path": "openapi_first.binder",
"docstring": "openapi_first.binder\n============================\n\nOpenAPI-driven route binding for FastAPI.\n\nThis module is responsible for translating an OpenAPI 3.x specification\ninto concrete FastAPI routes. It enforces a strict one-to-one mapping\nbetween OpenAPI operations and Python handler functions using operationId.\n\nCore responsibility\n-------------------\n- Read path + method definitions from an OpenAPI specification\n- Resolve each operationId to a Python callable\n- Register routes with FastAPI using APIRoute\n- Fail fast when contract violations are detected\n\nDesign constraints\n------------------\n- All routes MUST be declared in the OpenAPI specification.\n- All OpenAPI operations MUST define an operationId.\n- Every operationId MUST resolve to a handler function.\n- Handlers are plain Python callables (no decorators required).\n- No implicit route creation or inference is allowed.\n\nThis module intentionally does NOT:\n-------------------------------\n- Perform request or response validation\n- Generate Pydantic models\n- Modify FastAPI dependency injection\n- Interpret OpenAPI semantics beyond routing metadata\n\nThose concerns belong to other layers or tooling.",
"objects": {
"APIRoute": {
"name": "APIRoute",
"kind": "alias",
"path": "openapi_first.binder.APIRoute",
"signature": "<bound method Alias.signature of Alias('APIRoute', 'fastapi.routing.APIRoute')>",
"docstring": null
},
"MissingOperationHandler": {
"name": "MissingOperationHandler",
"kind": "class",
"path": "openapi_first.binder.MissingOperationHandler",
"signature": "<bound method Alias.signature of Alias('MissingOperationHandler', 'openapi_first.errors.MissingOperationHandler')>",
"docstring": "Raised when an OpenAPI operation cannot be resolved to a handler.\n\nThis error occurs when:\n- An OpenAPI operation does not define an operationId, or\n- An operationId is defined but no matching function exists in the\n provided routes module.\n\nThis represents a violation of the OpenAPI-first contract and\nindicates that the specification and implementation are out of sync."
},
"bind_routes": {
"name": "bind_routes",
"kind": "function",
"path": "openapi_first.binder.bind_routes",
"signature": "<bound method Function.signature of Function('bind_routes', 41, 102)>",
"docstring": "Bind OpenAPI operations to FastAPI routes.\n\nIterates through the OpenAPI specification paths and methods,\nresolves each operationId to a handler function, and registers\na corresponding APIRoute on the FastAPI application.\n\nParameters\n----------\napp : fastapi.FastAPI\n The FastAPI application instance to which routes will be added.\n\nspec : dict\n Parsed OpenAPI 3.x specification dictionary.\n\nroutes_module : module\n Python module containing handler functions. Each handler's\n name MUST exactly match an OpenAPI operationId.\n\nRaises\n------\nMissingOperationHandler\n If an operationId is missing from the spec or if no corresponding\n handler function exists in the routes module.\n\nBehavior guarantees\n-------------------\n- Route registration is deterministic and spec-driven.\n- No route decorators are required or supported.\n- Handler resolution errors surface at application startup."
},
"Any": {
"name": "Any",
"kind": "alias",
"path": "openapi_first.binder.Any",
"signature": "<bound method Alias.signature of Alias('Any', 'typing.Any')>",
"docstring": null
},
"Dict": {
"name": "Dict",
"kind": "alias",
"path": "openapi_first.binder.Dict",
"signature": "<bound method Alias.signature of Alias('Dict', 'typing.Dict')>",
"docstring": null
},
"FastAPI": {
"name": "FastAPI",
"kind": "alias",
"path": "openapi_first.binder.FastAPI",
"signature": "<bound method Alias.signature of Alias('FastAPI', 'fastapi.FastAPI')>",
"docstring": null
}
}
}
}

View File

@@ -0,0 +1,65 @@
{
"module": "openapi_first.cli",
"content": {
"path": "openapi_first.cli",
"docstring": "openapi_first.cli\n========================\n\nCommand-line interface for FastAPI OpenAPI-first scaffolding utilities.\n\nThis CLI bootstraps OpenAPI-first FastAPI applications from versioned,\nbundled templates packaged with the library.",
"objects": {
"argparse": {
"name": "argparse",
"kind": "alias",
"path": "openapi_first.cli.argparse",
"signature": "<bound method Alias.signature of Alias('argparse', 'argparse')>",
"docstring": null
},
"shutil": {
"name": "shutil",
"kind": "alias",
"path": "openapi_first.cli.shutil",
"signature": "<bound method Alias.signature of Alias('shutil', 'shutil')>",
"docstring": null
},
"Path": {
"name": "Path",
"kind": "alias",
"path": "openapi_first.cli.Path",
"signature": "<bound method Alias.signature of Alias('Path', 'pathlib.Path')>",
"docstring": null
},
"resources": {
"name": "resources",
"kind": "alias",
"path": "openapi_first.cli.resources",
"signature": "<bound method Alias.signature of Alias('resources', 'importlib.resources')>",
"docstring": null
},
"DEFAULT_TEMPLATE": {
"name": "DEFAULT_TEMPLATE",
"kind": "attribute",
"path": "openapi_first.cli.DEFAULT_TEMPLATE",
"signature": null,
"docstring": null
},
"available_templates": {
"name": "available_templates",
"kind": "function",
"path": "openapi_first.cli.available_templates",
"signature": "<bound method Function.signature of Function('available_templates', 20, 29)>",
"docstring": "Return a list of available application templates."
},
"copy_template": {
"name": "copy_template",
"kind": "function",
"path": "openapi_first.cli.copy_template",
"signature": "<bound method Function.signature of Function('copy_template', 32, 49)>",
"docstring": "Copy a bundled OpenAPI-first application template into a directory."
},
"main": {
"name": "main",
"kind": "function",
"path": "openapi_first.cli.main",
"signature": "<bound method Function.signature of Function('main', 52, 88)>",
"docstring": null
}
}
}
}

View File

@@ -0,0 +1,102 @@
{
"module": "openapi_first.client",
"content": {
"path": "openapi_first.client",
"docstring": null,
"objects": {
"Any": {
"name": "Any",
"kind": "alias",
"path": "openapi_first.client.Any",
"signature": "<bound method Alias.signature of Alias('Any', 'typing.Any')>",
"docstring": null
},
"Callable": {
"name": "Callable",
"kind": "alias",
"path": "openapi_first.client.Callable",
"signature": "<bound method Alias.signature of Alias('Callable', 'typing.Callable')>",
"docstring": null
},
"Dict": {
"name": "Dict",
"kind": "alias",
"path": "openapi_first.client.Dict",
"signature": "<bound method Alias.signature of Alias('Dict', 'typing.Dict')>",
"docstring": null
},
"Optional": {
"name": "Optional",
"kind": "alias",
"path": "openapi_first.client.Optional",
"signature": "<bound method Alias.signature of Alias('Optional', 'typing.Optional')>",
"docstring": null
},
"urljoin": {
"name": "urljoin",
"kind": "alias",
"path": "openapi_first.client.urljoin",
"signature": "<bound method Alias.signature of Alias('urljoin', 'urllib.parse.urljoin')>",
"docstring": null
},
"httpx": {
"name": "httpx",
"kind": "alias",
"path": "openapi_first.client.httpx",
"signature": "<bound method Alias.signature of Alias('httpx', 'httpx')>",
"docstring": null
},
"OpenAPIFirstError": {
"name": "OpenAPIFirstError",
"kind": "class",
"path": "openapi_first.client.OpenAPIFirstError",
"signature": "<bound method Alias.signature of Alias('OpenAPIFirstError', 'openapi_first.errors.OpenAPIFirstError')>",
"docstring": "Base exception for all OpenAPI-first enforcement errors.\n\nThis exception exists to allow callers, test suites, and CI pipelines\nto catch and distinguish OpenAPI contract violations from unrelated\nruntime errors.\n\nAll exceptions raised by the OpenAPI-first core should inherit from\nthis type."
},
"OpenAPIClientError": {
"name": "OpenAPIClientError",
"kind": "class",
"path": "openapi_first.client.OpenAPIClientError",
"signature": "<bound method Class.signature of Class('OpenAPIClientError', 9, 10)>",
"docstring": "Raised when an OpenAPI client operation fails."
},
"OpenAPIClient": {
"name": "OpenAPIClient",
"kind": "class",
"path": "openapi_first.client.OpenAPIClient",
"signature": "<bound method Class.signature of Class('OpenAPIClient', 13, 176)>",
"docstring": "OpenAPI-first HTTP client (httpx-based).\n\n- One callable per operationId\n- Explicit parameters (path, query, headers, body)\n- No implicit schema inference or mutation",
"members": {
"spec": {
"name": "spec",
"kind": "attribute",
"path": "openapi_first.client.OpenAPIClient.spec",
"signature": null,
"docstring": null
},
"base_url": {
"name": "base_url",
"kind": "attribute",
"path": "openapi_first.client.OpenAPIClient.base_url",
"signature": null,
"docstring": null
},
"client": {
"name": "client",
"kind": "attribute",
"path": "openapi_first.client.OpenAPIClient.client",
"signature": null,
"docstring": null
},
"operations": {
"name": "operations",
"kind": "function",
"path": "openapi_first.client.OpenAPIClient.operations",
"signature": "<bound method Function.signature of Function('operations', 45, 46)>",
"docstring": null
}
}
}
}
}
}

View File

@@ -0,0 +1,30 @@
{
"module": "openapi_first.errors",
"content": {
"path": "openapi_first.errors",
"docstring": "openapi_first.errors\n============================\n\nCustom exceptions for OpenAPI-first FastAPI applications.\n\nThis module defines a small hierarchy of explicit, intention-revealing\nexceptions used to signal contract violations between an OpenAPI\nspecification and its Python implementation.\n\nDesign principles\n-----------------\n- Errors represent *programmer mistakes*, not runtime conditions.\n- All errors are raised during application startup.\n- Messages are actionable and suitable for CI/CD output.\n- Exceptions are explicit rather than reused from generic built-ins.\n\nThese errors should normally cause immediate application failure.",
"objects": {
"OpenAPIFirstError": {
"name": "OpenAPIFirstError",
"kind": "class",
"path": "openapi_first.errors.OpenAPIFirstError",
"signature": "<bound method Class.signature of Class('OpenAPIFirstError', 21, 32)>",
"docstring": "Base exception for all OpenAPI-first enforcement errors.\n\nThis exception exists to allow callers, test suites, and CI pipelines\nto catch and distinguish OpenAPI contract violations from unrelated\nruntime errors.\n\nAll exceptions raised by the OpenAPI-first core should inherit from\nthis type."
},
"MissingOperationHandler": {
"name": "MissingOperationHandler",
"kind": "class",
"path": "openapi_first.errors.MissingOperationHandler",
"signature": "<bound method Class.signature of Class('MissingOperationHandler', 35, 72)>",
"docstring": "Raised when an OpenAPI operation cannot be resolved to a handler.\n\nThis error occurs when:\n- An OpenAPI operation does not define an operationId, or\n- An operationId is defined but no matching function exists in the\n provided routes module.\n\nThis represents a violation of the OpenAPI-first contract and\nindicates that the specification and implementation are out of sync."
},
"Optional": {
"name": "Optional",
"kind": "alias",
"path": "openapi_first.errors.Optional",
"signature": "<bound method Alias.signature of Alias('Optional', 'typing.Optional')>",
"docstring": null
}
}
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,79 @@
{
"module": "openapi_first.loader",
"content": {
"path": "openapi_first.loader",
"docstring": "openapi_first.loaders\n=============================\n\nOpenAPI specification loading and validation utilities.\n\nThis module is responsible for loading an OpenAPI 3.x specification\nfrom disk and validating it before it is used by the application.\n\nIt enforces the principle that an invalid or malformed OpenAPI document\nmust never reach the routing or runtime layers.\n\nDesign principles\n-----------------\n- OpenAPI is treated as an authoritative contract.\n- Invalid specifications fail fast at application startup.\n- Supported formats are JSON and YAML.\n- Validation errors are surfaced clearly and early.\n\nThis module intentionally does NOT:\n-----------------------------------\n- Modify the OpenAPI document\n- Infer missing fields\n- Generate models or code\n- Perform request/response validation at runtime",
"objects": {
"json": {
"name": "json",
"kind": "alias",
"path": "openapi_first.loader.json",
"signature": "<bound method Alias.signature of Alias('json', 'json')>",
"docstring": null
},
"Path": {
"name": "Path",
"kind": "alias",
"path": "openapi_first.loader.Path",
"signature": "<bound method Alias.signature of Alias('Path', 'pathlib.Path')>",
"docstring": null
},
"Any": {
"name": "Any",
"kind": "alias",
"path": "openapi_first.loader.Any",
"signature": "<bound method Alias.signature of Alias('Any', 'typing.Any')>",
"docstring": null
},
"yaml": {
"name": "yaml",
"kind": "alias",
"path": "openapi_first.loader.yaml",
"signature": "<bound method Alias.signature of Alias('yaml', 'yaml')>",
"docstring": null
},
"validate_spec": {
"name": "validate_spec",
"kind": "alias",
"path": "openapi_first.loader.validate_spec",
"signature": "<bound method Alias.signature of Alias('validate_spec', 'openapi_spec_validator.validate_spec')>",
"docstring": null
},
"OpenAPIFirstError": {
"name": "OpenAPIFirstError",
"kind": "class",
"path": "openapi_first.loader.OpenAPIFirstError",
"signature": "<bound method Alias.signature of Alias('OpenAPIFirstError', 'openapi_first.errors.OpenAPIFirstError')>",
"docstring": "Base exception for all OpenAPI-first enforcement errors.\n\nThis exception exists to allow callers, test suites, and CI pipelines\nto catch and distinguish OpenAPI contract violations from unrelated\nruntime errors.\n\nAll exceptions raised by the OpenAPI-first core should inherit from\nthis type."
},
"OpenAPISpecLoadError": {
"name": "OpenAPISpecLoadError",
"kind": "class",
"path": "openapi_first.loader.OpenAPISpecLoadError",
"signature": "<bound method Class.signature of Class('OpenAPISpecLoadError', 38, 45)>",
"docstring": "Raised when an OpenAPI specification cannot be loaded or validated.\n\nThis error indicates that the OpenAPI document is unreadable,\nmalformed, or violates the OpenAPI 3.x specification."
},
"load_openapi": {
"name": "load_openapi",
"kind": "function",
"path": "openapi_first.loader.load_openapi",
"signature": "<bound method Function.signature of Function('load_openapi', 48, 107)>",
"docstring": "Load and validate an OpenAPI 3.x specification from disk.\n\nThe specification is parsed based on file extension and validated\nusing a strict OpenAPI schema validator. Any error results in an\nimmediate exception, preventing application startup.\n\nParameters\n----------\npath : str or pathlib.Path\n Filesystem path to an OpenAPI specification file.\n Supported extensions:\n - `.json`\n - `.yaml`\n - `.yml`\n\nReturns\n-------\ndict\n Parsed and validated OpenAPI specification.\n\nRaises\n------\nOpenAPISpecLoadError\n If the file does not exist, cannot be parsed, or fails\n OpenAPI schema validation."
},
"Dict": {
"name": "Dict",
"kind": "alias",
"path": "openapi_first.loader.Dict",
"signature": "<bound method Alias.signature of Alias('Dict', 'typing.Dict')>",
"docstring": null
},
"Union": {
"name": "Union",
"kind": "alias",
"path": "openapi_first.loader.Union",
"signature": "<bound method Alias.signature of Alias('Union', 'typing.Union')>",
"docstring": null
}
}
}
}

View File

@@ -0,0 +1,51 @@
{
"module": "openapi_first.templates.crud_app.data",
"content": {
"path": "openapi_first.templates.crud_app.data",
"docstring": "In-memory mock data store for CRUD example.\n\nThis module intentionally avoids persistence and concurrency guarantees.\nIt is suitable for demos, tests, and scaffolding only.\n\nIt intentionally avoids\n- persistence\n- concurrency guarantees\n- validation\n- error handling\n\nThe implementation is suitable for:\n- demonstrations\n- tests\n- scaffolding and example services\n\nIt is explicitly NOT suitable for production use.\n\nThis module is not part of the ``openapi_first`` library API surface.",
"objects": {
"Dict": {
"name": "Dict",
"kind": "alias",
"path": "openapi_first.templates.crud_app.data.Dict",
"signature": "<bound method Alias.signature of Alias('Dict', 'typing.Dict')>",
"docstring": null
},
"list_items": {
"name": "list_items",
"kind": "function",
"path": "openapi_first.templates.crud_app.data.list_items",
"signature": "<bound method Function.signature of Function('list_items', 36, 48)>",
"docstring": "Return all items in the data store.\n\nThis function performs no filtering, pagination, or sorting.\nThe returned collection reflects the current in-memory state.\n\nReturns\n-------\nlist[dict]\n A list of item representations."
},
"get_item": {
"name": "get_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.data.get_item",
"signature": "<bound method Function.signature of Function('get_item', 51, 68)>",
"docstring": "Retrieve a single item by ID.\n\nThis function assumes the item exists and will raise ``KeyError``\nif the ID is not present in the store.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to retrieve.\n\nReturns\n-------\ndict\n The stored item representation."
},
"create_item": {
"name": "create_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.data.create_item",
"signature": "<bound method Function.signature of Function('create_item', 71, 92)>",
"docstring": "Create a new item in the data store.\n\nA new integer ID is assigned automatically. No validation is\nperformed on the provided payload.\n\nParameters\n----------\npayload : dict\n Item attributes excluding the ``id`` field.\n\nReturns\n-------\ndict\n The newly created item, including its assigned ID."
},
"update_item": {
"name": "update_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.data.update_item",
"signature": "<bound method Function.signature of Function('update_item', 95, 117)>",
"docstring": "Replace an existing item in the data store.\n\nThis function overwrites the existing item entirely and does not\nperform partial updates or validation. If the item does not exist,\nit will be created implicitly.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to update.\npayload : dict\n Item attributes excluding the ``id`` field.\n\nReturns\n-------\ndict\n The updated item representation."
},
"delete_item": {
"name": "delete_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.data.delete_item",
"signature": "<bound method Function.signature of Function('delete_item', 120, 132)>",
"docstring": "Remove an item from the data store.\n\nThis function assumes the item exists and will raise ``KeyError``\nif the ID is not present.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to delete."
}
}
}
}

View File

@@ -0,0 +1,273 @@
{
"module": "openapi_first.templates.crud_app",
"content": {
"path": "openapi_first.templates.crud_app",
"docstring": "OpenAPI-first CRUD application template.\n\nThis package contains a complete, minimal example of an OpenAPI-first\nCRUD service built using the ``openapi_first`` library.\n\nThe application is assembled exclusively from:\n- an OpenAPI specification (``openapi.yaml``)\n- a handler namespace implementing CRUD operations (``routes``)\n- an in-memory mock data store (``data``)\n\nAll HTTP routes, methods, schemas, and operation bindings are defined\nin the OpenAPI specification and enforced at application startup.\nNo decorator-driven routing or implicit framework behavior is used.\n\nThis template demonstrates:\n- operationId-driven server-side route binding\n- explicit HTTP status code control in handlers\n- operationId-driven client usage against the same OpenAPI contract\n- end-to-end validation using in-memory data and tests\n\n----------------------------------------------------------------------\nScaffolding via CLI\n----------------------------------------------------------------------\n\nCreate a new CRUD example service using the bundled template:\n\n openapi-first crud_app\n\nCreate the service in a custom directory:\n\n openapi-first crud_app my-crud-service\n\nList all available application templates:\n\n openapi-first --list\n\nThe CLI copies template files verbatim into the target directory.\nNo code is generated or modified beyond the copied scaffold.\n\n----------------------------------------------------------------------\nClient Usage Example\n----------------------------------------------------------------------\n\nThe same OpenAPI specification used by the server can be used to\nconstruct a strict, operationId-driven HTTP client.\n\nExample client calls for CRUD operations:\n\n from openapi_first.loader import load_openapi\n from openapi_first.client import OpenAPIClient\n\n spec = load_openapi(\"openapi.yaml\")\n client = OpenAPIClient(spec)\n\n # List items\n response = client.list_items()\n\n # Get item by ID\n response = client.get_item(\n path_params={\"item_id\": 1}\n )\n\n # Create item\n response = client.create_item(\n body={\"name\": \"Orange\", \"price\": 0.8}\n )\n\n # Update item\n response = client.update_item(\n path_params={\"item_id\": 1},\n body={\"name\": \"Green Apple\", \"price\": 0.6},\n )\n\n # Delete item\n response = client.delete_item(\n path_params={\"item_id\": 1}\n )\n\nClient guarantees:\n- One callable per OpenAPI ``operationId``\n- No hardcoded URLs or HTTP methods in user code\n- Path and request parameters must match the OpenAPI specification\n- Invalid or incomplete OpenAPI specs fail at client construction time\n\n----------------------------------------------------------------------\nNon-Goals\n----------------------------------------------------------------------\n\nThis template is intentionally minimal and is NOT:\n- production-ready\n- persistent or concurrency-safe\n- a reference architecture for data storage\n\nIt exists solely as a copyable example for learning, testing, and\nbootstrapping OpenAPI-first services.\n\nThis package is not part of the ``openapi_first`` library API surface.",
"objects": {
"data": {
"name": "data",
"kind": "module",
"path": "openapi_first.templates.crud_app.data",
"signature": null,
"docstring": "In-memory mock data store for CRUD example.\n\nThis module intentionally avoids persistence and concurrency guarantees.\nIt is suitable for demos, tests, and scaffolding only.\n\nIt intentionally avoids\n- persistence\n- concurrency guarantees\n- validation\n- error handling\n\nThe implementation is suitable for:\n- demonstrations\n- tests\n- scaffolding and example services\n\nIt is explicitly NOT suitable for production use.\n\nThis module is not part of the ``openapi_first`` library API surface.",
"members": {
"Dict": {
"name": "Dict",
"kind": "alias",
"path": "openapi_first.templates.crud_app.data.Dict",
"signature": "<bound method Alias.signature of Alias('Dict', 'typing.Dict')>",
"docstring": null
},
"list_items": {
"name": "list_items",
"kind": "function",
"path": "openapi_first.templates.crud_app.data.list_items",
"signature": "<bound method Function.signature of Function('list_items', 36, 48)>",
"docstring": "Return all items in the data store.\n\nThis function performs no filtering, pagination, or sorting.\nThe returned collection reflects the current in-memory state.\n\nReturns\n-------\nlist[dict]\n A list of item representations."
},
"get_item": {
"name": "get_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.data.get_item",
"signature": "<bound method Function.signature of Function('get_item', 51, 68)>",
"docstring": "Retrieve a single item by ID.\n\nThis function assumes the item exists and will raise ``KeyError``\nif the ID is not present in the store.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to retrieve.\n\nReturns\n-------\ndict\n The stored item representation."
},
"create_item": {
"name": "create_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.data.create_item",
"signature": "<bound method Function.signature of Function('create_item', 71, 92)>",
"docstring": "Create a new item in the data store.\n\nA new integer ID is assigned automatically. No validation is\nperformed on the provided payload.\n\nParameters\n----------\npayload : dict\n Item attributes excluding the ``id`` field.\n\nReturns\n-------\ndict\n The newly created item, including its assigned ID."
},
"update_item": {
"name": "update_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.data.update_item",
"signature": "<bound method Function.signature of Function('update_item', 95, 117)>",
"docstring": "Replace an existing item in the data store.\n\nThis function overwrites the existing item entirely and does not\nperform partial updates or validation. If the item does not exist,\nit will be created implicitly.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to update.\npayload : dict\n Item attributes excluding the ``id`` field.\n\nReturns\n-------\ndict\n The updated item representation."
},
"delete_item": {
"name": "delete_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.data.delete_item",
"signature": "<bound method Function.signature of Function('delete_item', 120, 132)>",
"docstring": "Remove an item from the data store.\n\nThis function assumes the item exists and will raise ``KeyError``\nif the ID is not present.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to delete."
}
}
},
"main": {
"name": "main",
"kind": "module",
"path": "openapi_first.templates.crud_app.main",
"signature": null,
"docstring": "Application entry point for an OpenAPI-first CRUD example service.\n\nThis module constructs a FastAPI application exclusively from an\nOpenAPI specification and a handler namespace, without using\ndecorator-driven routing.\n\nAll HTTP routes, methods, request/response schemas, and operation\nbindings are defined in the OpenAPI document referenced by\n``openapi_path``. Python callables defined in the ``routes`` module are\nbound to OpenAPI operations strictly via ``operationId``.\n\nThis module contains no routing logic, persistence concerns, or\nframework configuration beyond application assembly.\n\nDesign guarantees:\n- OpenAPI is the single source of truth\n- No undocumented routes can exist\n- Every OpenAPI operationId must resolve to exactly one handler\n- All contract violations fail at application startup\n\nThis file is intended to be used as the ASGI entry point.\n\nExample:\n uvicorn main:app",
"members": {
"OpenAPIFirstApp": {
"name": "OpenAPIFirstApp",
"kind": "class",
"path": "openapi_first.templates.crud_app.main.OpenAPIFirstApp",
"signature": "<bound method Alias.signature of Alias('OpenAPIFirstApp', 'openapi_first.app.OpenAPIFirstApp')>",
"docstring": "FastAPI application enforcing OpenAPI-first design.\n\n`OpenAPIFirstApp` subclasses FastAPI and replaces manual route\nregistration with OpenAPI-driven binding. All routes are derived\nfrom the provided OpenAPI specification, and each operationId is\nmapped to a Python function in the supplied routes module.\n\nParameters\n----------\nopenapi_path : str\n Filesystem path to the OpenAPI 3.x specification file.\n This specification is treated as the authoritative API contract.\n\nroutes_module : module\n Python module containing handler functions whose names correspond\n exactly to OpenAPI operationId values.\n\n**fastapi_kwargs\n Additional keyword arguments passed directly to `fastapi.FastAPI`\n (e.g., title, version, middleware, lifespan handlers).\n\nRaises\n------\nOpenAPIFirstError\n If the OpenAPI specification is invalid, or if any declared\n operationId does not have a corresponding handler function.\n\nBehavior guarantees\n-------------------\n- No route can exist without an OpenAPI declaration.\n- No OpenAPI operation can exist without a handler.\n- Swagger UI and `/openapi.json` always reflect the provided spec.\n- Handler functions remain framework-agnostic and testable.\n\nExample\n-------\n>>> from openapi_first import OpenAPIFirstApp\n>>> import app.routes as routes\n>>>\n>>> app = OpenAPIFirstApp(\n... openapi_path=\"app/openapi.json\",\n... routes_module=routes,\n... title=\"Example Service\"\n... )",
"members": {
"openapi": {
"name": "openapi",
"kind": "attribute",
"path": "openapi_first.templates.crud_app.main.OpenAPIFirstApp.openapi",
"signature": "<bound method Alias.signature of Alias('openapi', 'openapi_first.app.OpenAPIFirstApp.openapi')>",
"docstring": null
}
}
},
"routes": {
"name": "routes",
"kind": "alias",
"path": "openapi_first.templates.crud_app.main.routes",
"signature": "<bound method Alias.signature of Alias('routes', 'routes')>",
"docstring": null
},
"app": {
"name": "app",
"kind": "attribute",
"path": "openapi_first.templates.crud_app.main.app",
"signature": null,
"docstring": null
}
}
},
"routes": {
"name": "routes",
"kind": "module",
"path": "openapi_first.templates.crud_app.routes",
"signature": null,
"docstring": "CRUD route handlers bound via OpenAPI operationId.\n\nThese handlers explicitly control HTTP status codes to ensure\nruntime behavior matches the OpenAPI contract.\n\nThis module defines OpenAPI-bound operation handlers for a simple CRUD\nservice. Functions in this module are bound to HTTP routes exclusively\nvia OpenAPI ``operationId`` values.\n\nHandlers explicitly control HTTP response status codes to ensure runtime\nbehavior matches the OpenAPI contract. Error conditions are translated\ninto explicit HTTP responses rather than relying on implicit framework\nbehavior.\n\nNo routing decorators or path definitions appear in this module. All\nrouting, HTTP methods, and schemas are defined in the OpenAPI\nspecification.",
"members": {
"Response": {
"name": "Response",
"kind": "alias",
"path": "openapi_first.templates.crud_app.routes.Response",
"signature": "<bound method Alias.signature of Alias('Response', 'fastapi.Response')>",
"docstring": null
},
"HTTPException": {
"name": "HTTPException",
"kind": "alias",
"path": "openapi_first.templates.crud_app.routes.HTTPException",
"signature": "<bound method Alias.signature of Alias('HTTPException', 'fastapi.HTTPException')>",
"docstring": null
},
"list_items": {
"name": "list_items",
"kind": "function",
"path": "openapi_first.templates.crud_app.routes.list_items",
"signature": "<bound method Function.signature of Function('list_items', 32, 44)>",
"docstring": "List all items.\n\nImplements the OpenAPI operation identified by\n``operationId: list_items``.\n\nReturns\n-------\nlist[dict]\n A list of item representations."
},
"get_item": {
"name": "get_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.routes.get_item",
"signature": "<bound method Function.signature of Function('get_item', 47, 72)>",
"docstring": "Retrieve a single item by ID.\n\nImplements the OpenAPI operation identified by\n``operationId: get_item``.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to retrieve.\n\nReturns\n-------\ndict\n The requested item.\n\nRaises\n------\nHTTPException\n 404 if the item does not exist."
},
"create_item": {
"name": "create_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.routes.create_item",
"signature": "<bound method Function.signature of Function('create_item', 75, 96)>",
"docstring": "Create a new item.\n\nImplements the OpenAPI operation identified by\n``operationId: create_item``.\n\nParameters\n----------\npayload : dict\n Item attributes excluding the ``id`` field.\nresponse : fastapi.Response\n Response object used to set the HTTP status code.\n\nReturns\n-------\ndict\n The newly created item."
},
"update_item": {
"name": "update_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.routes.update_item",
"signature": "<bound method Function.signature of Function('update_item', 99, 126)>",
"docstring": "Update an existing item.\n\nImplements the OpenAPI operation identified by\n``operationId: update_item``.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to update.\npayload : dict\n Item attributes excluding the ``id`` field.\n\nReturns\n-------\ndict\n The updated item.\n\nRaises\n------\nHTTPException\n 404 if the item does not exist."
},
"delete_item": {
"name": "delete_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.routes.delete_item",
"signature": "<bound method Function.signature of Function('delete_item', 129, 158)>",
"docstring": "Delete an existing item.\n\nImplements the OpenAPI operation identified by\n``operationId: delete_item``.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to delete.\nresponse : fastapi.Response\n Response object used to set the HTTP status code.\n\nReturns\n-------\nNone\n No content.\n\nRaises\n------\nHTTPException\n 404 if the item does not exist."
}
}
},
"test_crud_app": {
"name": "test_crud_app",
"kind": "module",
"path": "openapi_first.templates.crud_app.test_crud_app",
"signature": null,
"docstring": "End-to-end tests for the OpenAPI-first CRUD example app.\n\nThese tests validate that all CRUD operations behave correctly\nagainst the in-memory mock data store.\n- OpenAPI specification loading\n- OperationId-driven route binding on the server\n- OperationId-driven client invocation\n- Correct HTTP status codes and response payloads\n\nThe tests exercise all CRUD operations against an in-memory mock data\nstore and assume deterministic behavior within a single process.\n\nThe tests assume:\n- OpenAPI-first route binding\n- In-memory storage (no persistence guarantees)\n- Deterministic behavior in a single process\n- One-to-one correspondence between OpenAPI operationId values and\n server/client callables",
"members": {
"TestClient": {
"name": "TestClient",
"kind": "alias",
"path": "openapi_first.templates.crud_app.test_crud_app.TestClient",
"signature": "<bound method Alias.signature of Alias('TestClient', 'fastapi.testclient.TestClient')>",
"docstring": null
},
"app": {
"name": "app",
"kind": "alias",
"path": "openapi_first.templates.crud_app.test_crud_app.app",
"signature": "<bound method Alias.signature of Alias('app', 'main.app')>",
"docstring": null
},
"load_openapi": {
"name": "load_openapi",
"kind": "function",
"path": "openapi_first.templates.crud_app.test_crud_app.load_openapi",
"signature": "<bound method Alias.signature of Alias('load_openapi', 'openapi_first.loader.load_openapi')>",
"docstring": "Load and validate an OpenAPI 3.x specification from disk.\n\nThe specification is parsed based on file extension and validated\nusing a strict OpenAPI schema validator. Any error results in an\nimmediate exception, preventing application startup.\n\nParameters\n----------\npath : str or pathlib.Path\n Filesystem path to an OpenAPI specification file.\n Supported extensions:\n - `.json`\n - `.yaml`\n - `.yml`\n\nReturns\n-------\ndict\n Parsed and validated OpenAPI specification.\n\nRaises\n------\nOpenAPISpecLoadError\n If the file does not exist, cannot be parsed, or fails\n OpenAPI schema validation."
},
"OpenAPIClient": {
"name": "OpenAPIClient",
"kind": "class",
"path": "openapi_first.templates.crud_app.test_crud_app.OpenAPIClient",
"signature": "<bound method Alias.signature of Alias('OpenAPIClient', 'openapi_first.client.OpenAPIClient')>",
"docstring": "OpenAPI-first HTTP client (httpx-based).\n\n- One callable per operationId\n- Explicit parameters (path, query, headers, body)\n- No implicit schema inference or mutation",
"members": {
"spec": {
"name": "spec",
"kind": "attribute",
"path": "openapi_first.templates.crud_app.test_crud_app.OpenAPIClient.spec",
"signature": "<bound method Alias.signature of Alias('spec', 'openapi_first.client.OpenAPIClient.spec')>",
"docstring": null
},
"base_url": {
"name": "base_url",
"kind": "attribute",
"path": "openapi_first.templates.crud_app.test_crud_app.OpenAPIClient.base_url",
"signature": "<bound method Alias.signature of Alias('base_url', 'openapi_first.client.OpenAPIClient.base_url')>",
"docstring": null
},
"client": {
"name": "client",
"kind": "attribute",
"path": "openapi_first.templates.crud_app.test_crud_app.OpenAPIClient.client",
"signature": "<bound method Alias.signature of Alias('client', 'openapi_first.client.OpenAPIClient.client')>",
"docstring": null
},
"operations": {
"name": "operations",
"kind": "function",
"path": "openapi_first.templates.crud_app.test_crud_app.OpenAPIClient.operations",
"signature": "<bound method Alias.signature of Alias('operations', 'openapi_first.client.OpenAPIClient.operations')>",
"docstring": null
}
}
},
"client": {
"name": "client",
"kind": "attribute",
"path": "openapi_first.templates.crud_app.test_crud_app.client",
"signature": null,
"docstring": null
},
"spec": {
"name": "spec",
"kind": "attribute",
"path": "openapi_first.templates.crud_app.test_crud_app.spec",
"signature": null,
"docstring": null
},
"test_list_items_initial": {
"name": "test_list_items_initial",
"kind": "function",
"path": "openapi_first.templates.crud_app.test_crud_app.test_list_items_initial",
"signature": "<bound method Function.signature of Function('test_list_items_initial', 38, 49)>",
"docstring": "Initial items should be present."
},
"test_get_item": {
"name": "test_get_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.test_crud_app.test_get_item",
"signature": "<bound method Function.signature of Function('test_get_item', 52, 62)>",
"docstring": "Existing item should be retrievable by ID."
},
"test_create_item": {
"name": "test_create_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.test_crud_app.test_create_item",
"signature": "<bound method Function.signature of Function('test_create_item', 65, 85)>",
"docstring": "Creating a new item should return the created entity."
},
"test_update_item": {
"name": "test_update_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.test_crud_app.test_update_item",
"signature": "<bound method Function.signature of Function('test_update_item', 88, 112)>",
"docstring": "Updating an item should replace its values."
},
"test_delete_item": {
"name": "test_delete_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.test_crud_app.test_delete_item",
"signature": "<bound method Function.signature of Function('test_delete_item', 115, 125)>",
"docstring": "Deleting an item should remove it from the store."
}
}
}
}
}
}

View File

@@ -0,0 +1,39 @@
{
"module": "openapi_first.templates.crud_app.main",
"content": {
"path": "openapi_first.templates.crud_app.main",
"docstring": "Application entry point for an OpenAPI-first CRUD example service.\n\nThis module constructs a FastAPI application exclusively from an\nOpenAPI specification and a handler namespace, without using\ndecorator-driven routing.\n\nAll HTTP routes, methods, request/response schemas, and operation\nbindings are defined in the OpenAPI document referenced by\n``openapi_path``. Python callables defined in the ``routes`` module are\nbound to OpenAPI operations strictly via ``operationId``.\n\nThis module contains no routing logic, persistence concerns, or\nframework configuration beyond application assembly.\n\nDesign guarantees:\n- OpenAPI is the single source of truth\n- No undocumented routes can exist\n- Every OpenAPI operationId must resolve to exactly one handler\n- All contract violations fail at application startup\n\nThis file is intended to be used as the ASGI entry point.\n\nExample:\n uvicorn main:app",
"objects": {
"OpenAPIFirstApp": {
"name": "OpenAPIFirstApp",
"kind": "class",
"path": "openapi_first.templates.crud_app.main.OpenAPIFirstApp",
"signature": "<bound method Alias.signature of Alias('OpenAPIFirstApp', 'openapi_first.app.OpenAPIFirstApp')>",
"docstring": "FastAPI application enforcing OpenAPI-first design.\n\n`OpenAPIFirstApp` subclasses FastAPI and replaces manual route\nregistration with OpenAPI-driven binding. All routes are derived\nfrom the provided OpenAPI specification, and each operationId is\nmapped to a Python function in the supplied routes module.\n\nParameters\n----------\nopenapi_path : str\n Filesystem path to the OpenAPI 3.x specification file.\n This specification is treated as the authoritative API contract.\n\nroutes_module : module\n Python module containing handler functions whose names correspond\n exactly to OpenAPI operationId values.\n\n**fastapi_kwargs\n Additional keyword arguments passed directly to `fastapi.FastAPI`\n (e.g., title, version, middleware, lifespan handlers).\n\nRaises\n------\nOpenAPIFirstError\n If the OpenAPI specification is invalid, or if any declared\n operationId does not have a corresponding handler function.\n\nBehavior guarantees\n-------------------\n- No route can exist without an OpenAPI declaration.\n- No OpenAPI operation can exist without a handler.\n- Swagger UI and `/openapi.json` always reflect the provided spec.\n- Handler functions remain framework-agnostic and testable.\n\nExample\n-------\n>>> from openapi_first import OpenAPIFirstApp\n>>> import app.routes as routes\n>>>\n>>> app = OpenAPIFirstApp(\n... openapi_path=\"app/openapi.json\",\n... routes_module=routes,\n... title=\"Example Service\"\n... )",
"members": {
"openapi": {
"name": "openapi",
"kind": "attribute",
"path": "openapi_first.templates.crud_app.main.OpenAPIFirstApp.openapi",
"signature": "<bound method Alias.signature of Alias('openapi', 'openapi_first.app.OpenAPIFirstApp.openapi')>",
"docstring": null
}
}
},
"routes": {
"name": "routes",
"kind": "alias",
"path": "openapi_first.templates.crud_app.main.routes",
"signature": "<bound method Alias.signature of Alias('routes', 'routes')>",
"docstring": null
},
"app": {
"name": "app",
"kind": "attribute",
"path": "openapi_first.templates.crud_app.main.app",
"signature": null,
"docstring": null
}
}
}
}

View File

@@ -0,0 +1,58 @@
{
"module": "openapi_first.templates.crud_app.routes",
"content": {
"path": "openapi_first.templates.crud_app.routes",
"docstring": "CRUD route handlers bound via OpenAPI operationId.\n\nThese handlers explicitly control HTTP status codes to ensure\nruntime behavior matches the OpenAPI contract.\n\nThis module defines OpenAPI-bound operation handlers for a simple CRUD\nservice. Functions in this module are bound to HTTP routes exclusively\nvia OpenAPI ``operationId`` values.\n\nHandlers explicitly control HTTP response status codes to ensure runtime\nbehavior matches the OpenAPI contract. Error conditions are translated\ninto explicit HTTP responses rather than relying on implicit framework\nbehavior.\n\nNo routing decorators or path definitions appear in this module. All\nrouting, HTTP methods, and schemas are defined in the OpenAPI\nspecification.",
"objects": {
"Response": {
"name": "Response",
"kind": "alias",
"path": "openapi_first.templates.crud_app.routes.Response",
"signature": "<bound method Alias.signature of Alias('Response', 'fastapi.Response')>",
"docstring": null
},
"HTTPException": {
"name": "HTTPException",
"kind": "alias",
"path": "openapi_first.templates.crud_app.routes.HTTPException",
"signature": "<bound method Alias.signature of Alias('HTTPException', 'fastapi.HTTPException')>",
"docstring": null
},
"list_items": {
"name": "list_items",
"kind": "function",
"path": "openapi_first.templates.crud_app.routes.list_items",
"signature": "<bound method Function.signature of Function('list_items', 32, 44)>",
"docstring": "List all items.\n\nImplements the OpenAPI operation identified by\n``operationId: list_items``.\n\nReturns\n-------\nlist[dict]\n A list of item representations."
},
"get_item": {
"name": "get_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.routes.get_item",
"signature": "<bound method Function.signature of Function('get_item', 47, 72)>",
"docstring": "Retrieve a single item by ID.\n\nImplements the OpenAPI operation identified by\n``operationId: get_item``.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to retrieve.\n\nReturns\n-------\ndict\n The requested item.\n\nRaises\n------\nHTTPException\n 404 if the item does not exist."
},
"create_item": {
"name": "create_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.routes.create_item",
"signature": "<bound method Function.signature of Function('create_item', 75, 96)>",
"docstring": "Create a new item.\n\nImplements the OpenAPI operation identified by\n``operationId: create_item``.\n\nParameters\n----------\npayload : dict\n Item attributes excluding the ``id`` field.\nresponse : fastapi.Response\n Response object used to set the HTTP status code.\n\nReturns\n-------\ndict\n The newly created item."
},
"update_item": {
"name": "update_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.routes.update_item",
"signature": "<bound method Function.signature of Function('update_item', 99, 126)>",
"docstring": "Update an existing item.\n\nImplements the OpenAPI operation identified by\n``operationId: update_item``.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to update.\npayload : dict\n Item attributes excluding the ``id`` field.\n\nReturns\n-------\ndict\n The updated item.\n\nRaises\n------\nHTTPException\n 404 if the item does not exist."
},
"delete_item": {
"name": "delete_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.routes.delete_item",
"signature": "<bound method Function.signature of Function('delete_item', 129, 158)>",
"docstring": "Delete an existing item.\n\nImplements the OpenAPI operation identified by\n``operationId: delete_item``.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to delete.\nresponse : fastapi.Response\n Response object used to set the HTTP status code.\n\nReturns\n-------\nNone\n No content.\n\nRaises\n------\nHTTPException\n 404 if the item does not exist."
}
}
}
}

View File

@@ -0,0 +1,116 @@
{
"module": "openapi_first.templates.crud_app.test_crud_app",
"content": {
"path": "openapi_first.templates.crud_app.test_crud_app",
"docstring": "End-to-end tests for the OpenAPI-first CRUD example app.\n\nThese tests validate that all CRUD operations behave correctly\nagainst the in-memory mock data store.\n- OpenAPI specification loading\n- OperationId-driven route binding on the server\n- OperationId-driven client invocation\n- Correct HTTP status codes and response payloads\n\nThe tests exercise all CRUD operations against an in-memory mock data\nstore and assume deterministic behavior within a single process.\n\nThe tests assume:\n- OpenAPI-first route binding\n- In-memory storage (no persistence guarantees)\n- Deterministic behavior in a single process\n- One-to-one correspondence between OpenAPI operationId values and\n server/client callables",
"objects": {
"TestClient": {
"name": "TestClient",
"kind": "alias",
"path": "openapi_first.templates.crud_app.test_crud_app.TestClient",
"signature": "<bound method Alias.signature of Alias('TestClient', 'fastapi.testclient.TestClient')>",
"docstring": null
},
"app": {
"name": "app",
"kind": "alias",
"path": "openapi_first.templates.crud_app.test_crud_app.app",
"signature": "<bound method Alias.signature of Alias('app', 'main.app')>",
"docstring": null
},
"load_openapi": {
"name": "load_openapi",
"kind": "function",
"path": "openapi_first.templates.crud_app.test_crud_app.load_openapi",
"signature": "<bound method Alias.signature of Alias('load_openapi', 'openapi_first.loader.load_openapi')>",
"docstring": "Load and validate an OpenAPI 3.x specification from disk.\n\nThe specification is parsed based on file extension and validated\nusing a strict OpenAPI schema validator. Any error results in an\nimmediate exception, preventing application startup.\n\nParameters\n----------\npath : str or pathlib.Path\n Filesystem path to an OpenAPI specification file.\n Supported extensions:\n - `.json`\n - `.yaml`\n - `.yml`\n\nReturns\n-------\ndict\n Parsed and validated OpenAPI specification.\n\nRaises\n------\nOpenAPISpecLoadError\n If the file does not exist, cannot be parsed, or fails\n OpenAPI schema validation."
},
"OpenAPIClient": {
"name": "OpenAPIClient",
"kind": "class",
"path": "openapi_first.templates.crud_app.test_crud_app.OpenAPIClient",
"signature": "<bound method Alias.signature of Alias('OpenAPIClient', 'openapi_first.client.OpenAPIClient')>",
"docstring": "OpenAPI-first HTTP client (httpx-based).\n\n- One callable per operationId\n- Explicit parameters (path, query, headers, body)\n- No implicit schema inference or mutation",
"members": {
"spec": {
"name": "spec",
"kind": "attribute",
"path": "openapi_first.templates.crud_app.test_crud_app.OpenAPIClient.spec",
"signature": "<bound method Alias.signature of Alias('spec', 'openapi_first.client.OpenAPIClient.spec')>",
"docstring": null
},
"base_url": {
"name": "base_url",
"kind": "attribute",
"path": "openapi_first.templates.crud_app.test_crud_app.OpenAPIClient.base_url",
"signature": "<bound method Alias.signature of Alias('base_url', 'openapi_first.client.OpenAPIClient.base_url')>",
"docstring": null
},
"client": {
"name": "client",
"kind": "attribute",
"path": "openapi_first.templates.crud_app.test_crud_app.OpenAPIClient.client",
"signature": "<bound method Alias.signature of Alias('client', 'openapi_first.client.OpenAPIClient.client')>",
"docstring": null
},
"operations": {
"name": "operations",
"kind": "function",
"path": "openapi_first.templates.crud_app.test_crud_app.OpenAPIClient.operations",
"signature": "<bound method Alias.signature of Alias('operations', 'openapi_first.client.OpenAPIClient.operations')>",
"docstring": null
}
}
},
"client": {
"name": "client",
"kind": "attribute",
"path": "openapi_first.templates.crud_app.test_crud_app.client",
"signature": null,
"docstring": null
},
"spec": {
"name": "spec",
"kind": "attribute",
"path": "openapi_first.templates.crud_app.test_crud_app.spec",
"signature": null,
"docstring": null
},
"test_list_items_initial": {
"name": "test_list_items_initial",
"kind": "function",
"path": "openapi_first.templates.crud_app.test_crud_app.test_list_items_initial",
"signature": "<bound method Function.signature of Function('test_list_items_initial', 38, 49)>",
"docstring": "Initial items should be present."
},
"test_get_item": {
"name": "test_get_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.test_crud_app.test_get_item",
"signature": "<bound method Function.signature of Function('test_get_item', 52, 62)>",
"docstring": "Existing item should be retrievable by ID."
},
"test_create_item": {
"name": "test_create_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.test_crud_app.test_create_item",
"signature": "<bound method Function.signature of Function('test_create_item', 65, 85)>",
"docstring": "Creating a new item should return the created entity."
},
"test_update_item": {
"name": "test_update_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.test_crud_app.test_update_item",
"signature": "<bound method Function.signature of Function('test_update_item', 88, 112)>",
"docstring": "Updating an item should replace its values."
},
"test_delete_item": {
"name": "test_delete_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.test_crud_app.test_delete_item",
"signature": "<bound method Function.signature of Function('test_delete_item', 115, 125)>",
"docstring": "Deleting an item should remove it from the store."
}
}
}
}

View File

@@ -0,0 +1,64 @@
{
"module": "openapi_first.templates.health_app",
"content": {
"path": "openapi_first.templates.health_app",
"docstring": "OpenAPI-first FastAPI application template.\n\nThis package contains a minimal, fully working example of an\nOpenAPI-first FastAPI service built using the ``openapi_first`` library.\n\nThe application is assembled exclusively from:\n- an OpenAPI specification (``openapi.yaml``)\n- a handler namespace (``routes``)\n\nNo routing decorators, implicit behavior, or framework-specific\nconvenience abstractions are used. All HTTP routes, methods, and\noperation bindings are defined in OpenAPI and enforced at application\nstartup.\n\nThis package is intended to be copied as a starting point for new\nservices via the ``openapi-first`` CLI. It is not part of the\n``openapi_first`` library API surface.\n\n----------------------------------------------------------------------\nScaffolding via CLI\n----------------------------------------------------------------------\n\nCreate a new OpenAPI-first health check service using the bundled\ntemplate:\n\n openapi-first health_app\n\nCreate the service in a custom directory:\n\n openapi-first health_app my-health-service\n\nList all available application templates:\n\n openapi-first --list\n\nThe CLI copies template files verbatim into the target directory.\nNo code is generated or modified beyond the copied scaffold.\n\n----------------------------------------------------------------------\nClient Usage Example\n----------------------------------------------------------------------\n\nThe same OpenAPI specification used by the server can be used to\nconstruct a strict, operationId-driven HTTP client.\n\nExample client call for the ``get_health`` operation:\n\n from openapi_first.loader import load_openapi\n from openapi_first.client import OpenAPIClient\n\n spec = load_openapi(\"openapi.yaml\")\n client = OpenAPIClient(spec)\n\n response = client.get_health()\n\n assert response.status_code == 200\n assert response.json() == {\"status\": \"ok\"}\n\nClient guarantees:\n- One callable per OpenAPI ``operationId``\n- No hardcoded URLs or HTTP methods in user code\n- Path and request parameters must match the OpenAPI specification\n- Invalid or incomplete OpenAPI specs fail at client construction time",
"objects": {
"main": {
"name": "main",
"kind": "module",
"path": "openapi_first.templates.health_app.main",
"signature": null,
"docstring": "Application entry point for an OpenAPI-first FastAPI service.\n\nThis module constructs a FastAPI application exclusively from an\nOpenAPI specification and a handler namespace, without using\ndecorator-driven routing.\n\nAll HTTP routes, methods, and operation bindings are defined in the\nOpenAPI document referenced by ``openapi_path``. Python callables\ndefined in the ``routes`` module are bound to OpenAPI operations\nstrictly via ``operationId``.\n\nThis module contains no routing logic, request handling, or framework\nconfiguration beyond application assembly.\n\nDesign guarantees:\n- OpenAPI is the single source of truth\n- No undocumented routes can exist\n- Every OpenAPI operationId must resolve to exactly one handler\n- All contract violations fail at application startup\n\nThis file is intended to be used as the ASGI entry point.\n\nExample:\n uvicorn main:app",
"members": {
"OpenAPIFirstApp": {
"name": "OpenAPIFirstApp",
"kind": "class",
"path": "openapi_first.templates.health_app.main.OpenAPIFirstApp",
"signature": "<bound method Alias.signature of Alias('OpenAPIFirstApp', 'openapi_first.app.OpenAPIFirstApp')>",
"docstring": "FastAPI application enforcing OpenAPI-first design.\n\n`OpenAPIFirstApp` subclasses FastAPI and replaces manual route\nregistration with OpenAPI-driven binding. All routes are derived\nfrom the provided OpenAPI specification, and each operationId is\nmapped to a Python function in the supplied routes module.\n\nParameters\n----------\nopenapi_path : str\n Filesystem path to the OpenAPI 3.x specification file.\n This specification is treated as the authoritative API contract.\n\nroutes_module : module\n Python module containing handler functions whose names correspond\n exactly to OpenAPI operationId values.\n\n**fastapi_kwargs\n Additional keyword arguments passed directly to `fastapi.FastAPI`\n (e.g., title, version, middleware, lifespan handlers).\n\nRaises\n------\nOpenAPIFirstError\n If the OpenAPI specification is invalid, or if any declared\n operationId does not have a corresponding handler function.\n\nBehavior guarantees\n-------------------\n- No route can exist without an OpenAPI declaration.\n- No OpenAPI operation can exist without a handler.\n- Swagger UI and `/openapi.json` always reflect the provided spec.\n- Handler functions remain framework-agnostic and testable.\n\nExample\n-------\n>>> from openapi_first import OpenAPIFirstApp\n>>> import app.routes as routes\n>>>\n>>> app = OpenAPIFirstApp(\n... openapi_path=\"app/openapi.json\",\n... routes_module=routes,\n... title=\"Example Service\"\n... )",
"members": {
"openapi": {
"name": "openapi",
"kind": "attribute",
"path": "openapi_first.templates.health_app.main.OpenAPIFirstApp.openapi",
"signature": "<bound method Alias.signature of Alias('openapi', 'openapi_first.app.OpenAPIFirstApp.openapi')>",
"docstring": null
}
}
},
"routes": {
"name": "routes",
"kind": "alias",
"path": "openapi_first.templates.health_app.main.routes",
"signature": "<bound method Alias.signature of Alias('routes', 'routes')>",
"docstring": null
},
"app": {
"name": "app",
"kind": "attribute",
"path": "openapi_first.templates.health_app.main.app",
"signature": null,
"docstring": null
}
}
},
"routes": {
"name": "routes",
"kind": "module",
"path": "openapi_first.templates.health_app.routes",
"signature": null,
"docstring": "OpenAPI operation handlers.\n\nThis module defines pure Python callables that implement OpenAPI\noperations for this service. Functions in this module are bound to HTTP\nroutes exclusively via OpenAPI ``operationId`` values.\n\nNo routing decorators, HTTP metadata, or framework-specific logic\nshould appear here. All request/response semantics are defined in the\nOpenAPI specification.\n\nThis module serves solely as an operationId namespace.",
"members": {
"get_health": {
"name": "get_health",
"kind": "function",
"path": "openapi_first.templates.health_app.routes.get_health",
"signature": "<bound method Function.signature of Function('get_health', 16, 32)>",
"docstring": "Health check operation handler.\n\nThis function implements the OpenAPI operation identified by\n``operationId: get_health``.\n\nIt contains no routing metadata or framework-specific logic.\nRequest binding, HTTP method, and response semantics are defined\nexclusively by the OpenAPI specification.\n\nReturns\n-------\ndict\n A minimal liveness payload indicating service health."
}
}
}
}
}
}

View File

@@ -0,0 +1,39 @@
{
"module": "openapi_first.templates.health_app.main",
"content": {
"path": "openapi_first.templates.health_app.main",
"docstring": "Application entry point for an OpenAPI-first FastAPI service.\n\nThis module constructs a FastAPI application exclusively from an\nOpenAPI specification and a handler namespace, without using\ndecorator-driven routing.\n\nAll HTTP routes, methods, and operation bindings are defined in the\nOpenAPI document referenced by ``openapi_path``. Python callables\ndefined in the ``routes`` module are bound to OpenAPI operations\nstrictly via ``operationId``.\n\nThis module contains no routing logic, request handling, or framework\nconfiguration beyond application assembly.\n\nDesign guarantees:\n- OpenAPI is the single source of truth\n- No undocumented routes can exist\n- Every OpenAPI operationId must resolve to exactly one handler\n- All contract violations fail at application startup\n\nThis file is intended to be used as the ASGI entry point.\n\nExample:\n uvicorn main:app",
"objects": {
"OpenAPIFirstApp": {
"name": "OpenAPIFirstApp",
"kind": "class",
"path": "openapi_first.templates.health_app.main.OpenAPIFirstApp",
"signature": "<bound method Alias.signature of Alias('OpenAPIFirstApp', 'openapi_first.app.OpenAPIFirstApp')>",
"docstring": "FastAPI application enforcing OpenAPI-first design.\n\n`OpenAPIFirstApp` subclasses FastAPI and replaces manual route\nregistration with OpenAPI-driven binding. All routes are derived\nfrom the provided OpenAPI specification, and each operationId is\nmapped to a Python function in the supplied routes module.\n\nParameters\n----------\nopenapi_path : str\n Filesystem path to the OpenAPI 3.x specification file.\n This specification is treated as the authoritative API contract.\n\nroutes_module : module\n Python module containing handler functions whose names correspond\n exactly to OpenAPI operationId values.\n\n**fastapi_kwargs\n Additional keyword arguments passed directly to `fastapi.FastAPI`\n (e.g., title, version, middleware, lifespan handlers).\n\nRaises\n------\nOpenAPIFirstError\n If the OpenAPI specification is invalid, or if any declared\n operationId does not have a corresponding handler function.\n\nBehavior guarantees\n-------------------\n- No route can exist without an OpenAPI declaration.\n- No OpenAPI operation can exist without a handler.\n- Swagger UI and `/openapi.json` always reflect the provided spec.\n- Handler functions remain framework-agnostic and testable.\n\nExample\n-------\n>>> from openapi_first import OpenAPIFirstApp\n>>> import app.routes as routes\n>>>\n>>> app = OpenAPIFirstApp(\n... openapi_path=\"app/openapi.json\",\n... routes_module=routes,\n... title=\"Example Service\"\n... )",
"members": {
"openapi": {
"name": "openapi",
"kind": "attribute",
"path": "openapi_first.templates.health_app.main.OpenAPIFirstApp.openapi",
"signature": "<bound method Alias.signature of Alias('openapi', 'openapi_first.app.OpenAPIFirstApp.openapi')>",
"docstring": null
}
}
},
"routes": {
"name": "routes",
"kind": "alias",
"path": "openapi_first.templates.health_app.main.routes",
"signature": "<bound method Alias.signature of Alias('routes', 'routes')>",
"docstring": null
},
"app": {
"name": "app",
"kind": "attribute",
"path": "openapi_first.templates.health_app.main.app",
"signature": null,
"docstring": null
}
}
}
}

View File

@@ -0,0 +1,16 @@
{
"module": "openapi_first.templates.health_app.routes",
"content": {
"path": "openapi_first.templates.health_app.routes",
"docstring": "OpenAPI operation handlers.\n\nThis module defines pure Python callables that implement OpenAPI\noperations for this service. Functions in this module are bound to HTTP\nroutes exclusively via OpenAPI ``operationId`` values.\n\nNo routing decorators, HTTP metadata, or framework-specific logic\nshould appear here. All request/response semantics are defined in the\nOpenAPI specification.\n\nThis module serves solely as an operationId namespace.",
"objects": {
"get_health": {
"name": "get_health",
"kind": "function",
"path": "openapi_first.templates.health_app.routes.get_health",
"signature": "<bound method Function.signature of Function('get_health', 16, 32)>",
"docstring": "Health check operation handler.\n\nThis function implements the OpenAPI operation identified by\n``operationId: get_health``.\n\nIt contains no routing metadata or framework-specific logic.\nRequest binding, HTTP method, and response semantics are defined\nexclusively by the OpenAPI specification.\n\nReturns\n-------\ndict\n A minimal liveness payload indicating service health."
}
}
}
}

View File

@@ -0,0 +1,702 @@
{
"module": "openapi_first.templates",
"content": {
"path": "openapi_first.templates",
"docstring": "Application templates for FastAPI OpenAPI First.\n\nThis package contains example and scaffolding templates intended to be\ncopied into user projects via the ``openapi-first`` CLI.\n\nTemplates in this package are:\n- Reference implementations of OpenAPI-first services\n- Not part of the ``openapi_first`` public or internal API\n- Not intended to be imported as runtime dependencies\n\nThe presence of this file exists solely to:\n- Mark the directory as an explicit Python package\n- Enable deterministic tooling behavior (documentation, packaging)\n- Avoid accidental traversal of non-package directories\n\nNo code in this package should be imported by library consumers.",
"objects": {
"crud_app": {
"name": "crud_app",
"kind": "module",
"path": "openapi_first.templates.crud_app",
"signature": null,
"docstring": "OpenAPI-first CRUD application template.\n\nThis package contains a complete, minimal example of an OpenAPI-first\nCRUD service built using the ``openapi_first`` library.\n\nThe application is assembled exclusively from:\n- an OpenAPI specification (``openapi.yaml``)\n- a handler namespace implementing CRUD operations (``routes``)\n- an in-memory mock data store (``data``)\n\nAll HTTP routes, methods, schemas, and operation bindings are defined\nin the OpenAPI specification and enforced at application startup.\nNo decorator-driven routing or implicit framework behavior is used.\n\nThis template demonstrates:\n- operationId-driven server-side route binding\n- explicit HTTP status code control in handlers\n- operationId-driven client usage against the same OpenAPI contract\n- end-to-end validation using in-memory data and tests\n\n----------------------------------------------------------------------\nScaffolding via CLI\n----------------------------------------------------------------------\n\nCreate a new CRUD example service using the bundled template:\n\n openapi-first crud_app\n\nCreate the service in a custom directory:\n\n openapi-first crud_app my-crud-service\n\nList all available application templates:\n\n openapi-first --list\n\nThe CLI copies template files verbatim into the target directory.\nNo code is generated or modified beyond the copied scaffold.\n\n----------------------------------------------------------------------\nClient Usage Example\n----------------------------------------------------------------------\n\nThe same OpenAPI specification used by the server can be used to\nconstruct a strict, operationId-driven HTTP client.\n\nExample client calls for CRUD operations:\n\n from openapi_first.loader import load_openapi\n from openapi_first.client import OpenAPIClient\n\n spec = load_openapi(\"openapi.yaml\")\n client = OpenAPIClient(spec)\n\n # List items\n response = client.list_items()\n\n # Get item by ID\n response = client.get_item(\n path_params={\"item_id\": 1}\n )\n\n # Create item\n response = client.create_item(\n body={\"name\": \"Orange\", \"price\": 0.8}\n )\n\n # Update item\n response = client.update_item(\n path_params={\"item_id\": 1},\n body={\"name\": \"Green Apple\", \"price\": 0.6},\n )\n\n # Delete item\n response = client.delete_item(\n path_params={\"item_id\": 1}\n )\n\nClient guarantees:\n- One callable per OpenAPI ``operationId``\n- No hardcoded URLs or HTTP methods in user code\n- Path and request parameters must match the OpenAPI specification\n- Invalid or incomplete OpenAPI specs fail at client construction time\n\n----------------------------------------------------------------------\nNon-Goals\n----------------------------------------------------------------------\n\nThis template is intentionally minimal and is NOT:\n- production-ready\n- persistent or concurrency-safe\n- a reference architecture for data storage\n\nIt exists solely as a copyable example for learning, testing, and\nbootstrapping OpenAPI-first services.\n\nThis package is not part of the ``openapi_first`` library API surface.",
"members": {
"data": {
"name": "data",
"kind": "module",
"path": "openapi_first.templates.crud_app.data",
"signature": null,
"docstring": "In-memory mock data store for CRUD example.\n\nThis module intentionally avoids persistence and concurrency guarantees.\nIt is suitable for demos, tests, and scaffolding only.\n\nIt intentionally avoids\n- persistence\n- concurrency guarantees\n- validation\n- error handling\n\nThe implementation is suitable for:\n- demonstrations\n- tests\n- scaffolding and example services\n\nIt is explicitly NOT suitable for production use.\n\nThis module is not part of the ``openapi_first`` library API surface.",
"members": {
"Dict": {
"name": "Dict",
"kind": "alias",
"path": "openapi_first.templates.crud_app.data.Dict",
"signature": "<bound method Alias.signature of Alias('Dict', 'typing.Dict')>",
"docstring": null
},
"list_items": {
"name": "list_items",
"kind": "function",
"path": "openapi_first.templates.crud_app.data.list_items",
"signature": "<bound method Function.signature of Function('list_items', 36, 48)>",
"docstring": "Return all items in the data store.\n\nThis function performs no filtering, pagination, or sorting.\nThe returned collection reflects the current in-memory state.\n\nReturns\n-------\nlist[dict]\n A list of item representations."
},
"get_item": {
"name": "get_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.data.get_item",
"signature": "<bound method Function.signature of Function('get_item', 51, 68)>",
"docstring": "Retrieve a single item by ID.\n\nThis function assumes the item exists and will raise ``KeyError``\nif the ID is not present in the store.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to retrieve.\n\nReturns\n-------\ndict\n The stored item representation."
},
"create_item": {
"name": "create_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.data.create_item",
"signature": "<bound method Function.signature of Function('create_item', 71, 92)>",
"docstring": "Create a new item in the data store.\n\nA new integer ID is assigned automatically. No validation is\nperformed on the provided payload.\n\nParameters\n----------\npayload : dict\n Item attributes excluding the ``id`` field.\n\nReturns\n-------\ndict\n The newly created item, including its assigned ID."
},
"update_item": {
"name": "update_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.data.update_item",
"signature": "<bound method Function.signature of Function('update_item', 95, 117)>",
"docstring": "Replace an existing item in the data store.\n\nThis function overwrites the existing item entirely and does not\nperform partial updates or validation. If the item does not exist,\nit will be created implicitly.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to update.\npayload : dict\n Item attributes excluding the ``id`` field.\n\nReturns\n-------\ndict\n The updated item representation."
},
"delete_item": {
"name": "delete_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.data.delete_item",
"signature": "<bound method Function.signature of Function('delete_item', 120, 132)>",
"docstring": "Remove an item from the data store.\n\nThis function assumes the item exists and will raise ``KeyError``\nif the ID is not present.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to delete."
}
}
},
"main": {
"name": "main",
"kind": "module",
"path": "openapi_first.templates.crud_app.main",
"signature": null,
"docstring": "Application entry point for an OpenAPI-first CRUD example service.\n\nThis module constructs a FastAPI application exclusively from an\nOpenAPI specification and a handler namespace, without using\ndecorator-driven routing.\n\nAll HTTP routes, methods, request/response schemas, and operation\nbindings are defined in the OpenAPI document referenced by\n``openapi_path``. Python callables defined in the ``routes`` module are\nbound to OpenAPI operations strictly via ``operationId``.\n\nThis module contains no routing logic, persistence concerns, or\nframework configuration beyond application assembly.\n\nDesign guarantees:\n- OpenAPI is the single source of truth\n- No undocumented routes can exist\n- Every OpenAPI operationId must resolve to exactly one handler\n- All contract violations fail at application startup\n\nThis file is intended to be used as the ASGI entry point.\n\nExample:\n uvicorn main:app",
"members": {
"OpenAPIFirstApp": {
"name": "OpenAPIFirstApp",
"kind": "class",
"path": "openapi_first.templates.crud_app.main.OpenAPIFirstApp",
"signature": "<bound method Alias.signature of Alias('OpenAPIFirstApp', 'openapi_first.app.OpenAPIFirstApp')>",
"docstring": "FastAPI application enforcing OpenAPI-first design.\n\n`OpenAPIFirstApp` subclasses FastAPI and replaces manual route\nregistration with OpenAPI-driven binding. All routes are derived\nfrom the provided OpenAPI specification, and each operationId is\nmapped to a Python function in the supplied routes module.\n\nParameters\n----------\nopenapi_path : str\n Filesystem path to the OpenAPI 3.x specification file.\n This specification is treated as the authoritative API contract.\n\nroutes_module : module\n Python module containing handler functions whose names correspond\n exactly to OpenAPI operationId values.\n\n**fastapi_kwargs\n Additional keyword arguments passed directly to `fastapi.FastAPI`\n (e.g., title, version, middleware, lifespan handlers).\n\nRaises\n------\nOpenAPIFirstError\n If the OpenAPI specification is invalid, or if any declared\n operationId does not have a corresponding handler function.\n\nBehavior guarantees\n-------------------\n- No route can exist without an OpenAPI declaration.\n- No OpenAPI operation can exist without a handler.\n- Swagger UI and `/openapi.json` always reflect the provided spec.\n- Handler functions remain framework-agnostic and testable.\n\nExample\n-------\n>>> from openapi_first import OpenAPIFirstApp\n>>> import app.routes as routes\n>>>\n>>> app = OpenAPIFirstApp(\n... openapi_path=\"app/openapi.json\",\n... routes_module=routes,\n... title=\"Example Service\"\n... )",
"members": {
"openapi": {
"name": "openapi",
"kind": "attribute",
"path": "openapi_first.templates.crud_app.main.OpenAPIFirstApp.openapi",
"signature": "<bound method Alias.signature of Alias('openapi', 'openapi_first.app.OpenAPIFirstApp.openapi')>",
"docstring": null
}
}
},
"routes": {
"name": "routes",
"kind": "alias",
"path": "openapi_first.templates.crud_app.main.routes",
"signature": "<bound method Alias.signature of Alias('routes', 'routes')>",
"docstring": null
},
"app": {
"name": "app",
"kind": "attribute",
"path": "openapi_first.templates.crud_app.main.app",
"signature": null,
"docstring": null
}
}
},
"routes": {
"name": "routes",
"kind": "module",
"path": "openapi_first.templates.crud_app.routes",
"signature": null,
"docstring": "CRUD route handlers bound via OpenAPI operationId.\n\nThese handlers explicitly control HTTP status codes to ensure\nruntime behavior matches the OpenAPI contract.\n\nThis module defines OpenAPI-bound operation handlers for a simple CRUD\nservice. Functions in this module are bound to HTTP routes exclusively\nvia OpenAPI ``operationId`` values.\n\nHandlers explicitly control HTTP response status codes to ensure runtime\nbehavior matches the OpenAPI contract. Error conditions are translated\ninto explicit HTTP responses rather than relying on implicit framework\nbehavior.\n\nNo routing decorators or path definitions appear in this module. All\nrouting, HTTP methods, and schemas are defined in the OpenAPI\nspecification.",
"members": {
"Response": {
"name": "Response",
"kind": "alias",
"path": "openapi_first.templates.crud_app.routes.Response",
"signature": "<bound method Alias.signature of Alias('Response', 'fastapi.Response')>",
"docstring": null
},
"HTTPException": {
"name": "HTTPException",
"kind": "alias",
"path": "openapi_first.templates.crud_app.routes.HTTPException",
"signature": "<bound method Alias.signature of Alias('HTTPException', 'fastapi.HTTPException')>",
"docstring": null
},
"list_items": {
"name": "list_items",
"kind": "function",
"path": "openapi_first.templates.crud_app.routes.list_items",
"signature": "<bound method Function.signature of Function('list_items', 32, 44)>",
"docstring": "List all items.\n\nImplements the OpenAPI operation identified by\n``operationId: list_items``.\n\nReturns\n-------\nlist[dict]\n A list of item representations."
},
"get_item": {
"name": "get_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.routes.get_item",
"signature": "<bound method Function.signature of Function('get_item', 47, 72)>",
"docstring": "Retrieve a single item by ID.\n\nImplements the OpenAPI operation identified by\n``operationId: get_item``.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to retrieve.\n\nReturns\n-------\ndict\n The requested item.\n\nRaises\n------\nHTTPException\n 404 if the item does not exist."
},
"create_item": {
"name": "create_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.routes.create_item",
"signature": "<bound method Function.signature of Function('create_item', 75, 96)>",
"docstring": "Create a new item.\n\nImplements the OpenAPI operation identified by\n``operationId: create_item``.\n\nParameters\n----------\npayload : dict\n Item attributes excluding the ``id`` field.\nresponse : fastapi.Response\n Response object used to set the HTTP status code.\n\nReturns\n-------\ndict\n The newly created item."
},
"update_item": {
"name": "update_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.routes.update_item",
"signature": "<bound method Function.signature of Function('update_item', 99, 126)>",
"docstring": "Update an existing item.\n\nImplements the OpenAPI operation identified by\n``operationId: update_item``.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to update.\npayload : dict\n Item attributes excluding the ``id`` field.\n\nReturns\n-------\ndict\n The updated item.\n\nRaises\n------\nHTTPException\n 404 if the item does not exist."
},
"delete_item": {
"name": "delete_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.routes.delete_item",
"signature": "<bound method Function.signature of Function('delete_item', 129, 158)>",
"docstring": "Delete an existing item.\n\nImplements the OpenAPI operation identified by\n``operationId: delete_item``.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to delete.\nresponse : fastapi.Response\n Response object used to set the HTTP status code.\n\nReturns\n-------\nNone\n No content.\n\nRaises\n------\nHTTPException\n 404 if the item does not exist."
}
}
},
"test_crud_app": {
"name": "test_crud_app",
"kind": "module",
"path": "openapi_first.templates.crud_app.test_crud_app",
"signature": null,
"docstring": "End-to-end tests for the OpenAPI-first CRUD example app.\n\nThese tests validate that all CRUD operations behave correctly\nagainst the in-memory mock data store.\n- OpenAPI specification loading\n- OperationId-driven route binding on the server\n- OperationId-driven client invocation\n- Correct HTTP status codes and response payloads\n\nThe tests exercise all CRUD operations against an in-memory mock data\nstore and assume deterministic behavior within a single process.\n\nThe tests assume:\n- OpenAPI-first route binding\n- In-memory storage (no persistence guarantees)\n- Deterministic behavior in a single process\n- One-to-one correspondence between OpenAPI operationId values and\n server/client callables",
"members": {
"TestClient": {
"name": "TestClient",
"kind": "alias",
"path": "openapi_first.templates.crud_app.test_crud_app.TestClient",
"signature": "<bound method Alias.signature of Alias('TestClient', 'fastapi.testclient.TestClient')>",
"docstring": null
},
"app": {
"name": "app",
"kind": "alias",
"path": "openapi_first.templates.crud_app.test_crud_app.app",
"signature": "<bound method Alias.signature of Alias('app', 'main.app')>",
"docstring": null
},
"load_openapi": {
"name": "load_openapi",
"kind": "function",
"path": "openapi_first.templates.crud_app.test_crud_app.load_openapi",
"signature": "<bound method Alias.signature of Alias('load_openapi', 'openapi_first.loader.load_openapi')>",
"docstring": "Load and validate an OpenAPI 3.x specification from disk.\n\nThe specification is parsed based on file extension and validated\nusing a strict OpenAPI schema validator. Any error results in an\nimmediate exception, preventing application startup.\n\nParameters\n----------\npath : str or pathlib.Path\n Filesystem path to an OpenAPI specification file.\n Supported extensions:\n - `.json`\n - `.yaml`\n - `.yml`\n\nReturns\n-------\ndict\n Parsed and validated OpenAPI specification.\n\nRaises\n------\nOpenAPISpecLoadError\n If the file does not exist, cannot be parsed, or fails\n OpenAPI schema validation."
},
"OpenAPIClient": {
"name": "OpenAPIClient",
"kind": "class",
"path": "openapi_first.templates.crud_app.test_crud_app.OpenAPIClient",
"signature": "<bound method Alias.signature of Alias('OpenAPIClient', 'openapi_first.client.OpenAPIClient')>",
"docstring": "OpenAPI-first HTTP client (httpx-based).\n\n- One callable per operationId\n- Explicit parameters (path, query, headers, body)\n- No implicit schema inference or mutation",
"members": {
"spec": {
"name": "spec",
"kind": "attribute",
"path": "openapi_first.templates.crud_app.test_crud_app.OpenAPIClient.spec",
"signature": "<bound method Alias.signature of Alias('spec', 'openapi_first.client.OpenAPIClient.spec')>",
"docstring": null
},
"base_url": {
"name": "base_url",
"kind": "attribute",
"path": "openapi_first.templates.crud_app.test_crud_app.OpenAPIClient.base_url",
"signature": "<bound method Alias.signature of Alias('base_url', 'openapi_first.client.OpenAPIClient.base_url')>",
"docstring": null
},
"client": {
"name": "client",
"kind": "attribute",
"path": "openapi_first.templates.crud_app.test_crud_app.OpenAPIClient.client",
"signature": "<bound method Alias.signature of Alias('client', 'openapi_first.client.OpenAPIClient.client')>",
"docstring": null
},
"operations": {
"name": "operations",
"kind": "function",
"path": "openapi_first.templates.crud_app.test_crud_app.OpenAPIClient.operations",
"signature": "<bound method Alias.signature of Alias('operations', 'openapi_first.client.OpenAPIClient.operations')>",
"docstring": null
}
}
},
"client": {
"name": "client",
"kind": "attribute",
"path": "openapi_first.templates.crud_app.test_crud_app.client",
"signature": null,
"docstring": null
},
"spec": {
"name": "spec",
"kind": "attribute",
"path": "openapi_first.templates.crud_app.test_crud_app.spec",
"signature": null,
"docstring": null
},
"test_list_items_initial": {
"name": "test_list_items_initial",
"kind": "function",
"path": "openapi_first.templates.crud_app.test_crud_app.test_list_items_initial",
"signature": "<bound method Function.signature of Function('test_list_items_initial', 38, 49)>",
"docstring": "Initial items should be present."
},
"test_get_item": {
"name": "test_get_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.test_crud_app.test_get_item",
"signature": "<bound method Function.signature of Function('test_get_item', 52, 62)>",
"docstring": "Existing item should be retrievable by ID."
},
"test_create_item": {
"name": "test_create_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.test_crud_app.test_create_item",
"signature": "<bound method Function.signature of Function('test_create_item', 65, 85)>",
"docstring": "Creating a new item should return the created entity."
},
"test_update_item": {
"name": "test_update_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.test_crud_app.test_update_item",
"signature": "<bound method Function.signature of Function('test_update_item', 88, 112)>",
"docstring": "Updating an item should replace its values."
},
"test_delete_item": {
"name": "test_delete_item",
"kind": "function",
"path": "openapi_first.templates.crud_app.test_crud_app.test_delete_item",
"signature": "<bound method Function.signature of Function('test_delete_item', 115, 125)>",
"docstring": "Deleting an item should remove it from the store."
}
}
}
}
},
"health_app": {
"name": "health_app",
"kind": "module",
"path": "openapi_first.templates.health_app",
"signature": null,
"docstring": "OpenAPI-first FastAPI application template.\n\nThis package contains a minimal, fully working example of an\nOpenAPI-first FastAPI service built using the ``openapi_first`` library.\n\nThe application is assembled exclusively from:\n- an OpenAPI specification (``openapi.yaml``)\n- a handler namespace (``routes``)\n\nNo routing decorators, implicit behavior, or framework-specific\nconvenience abstractions are used. All HTTP routes, methods, and\noperation bindings are defined in OpenAPI and enforced at application\nstartup.\n\nThis package is intended to be copied as a starting point for new\nservices via the ``openapi-first`` CLI. It is not part of the\n``openapi_first`` library API surface.\n\n----------------------------------------------------------------------\nScaffolding via CLI\n----------------------------------------------------------------------\n\nCreate a new OpenAPI-first health check service using the bundled\ntemplate:\n\n openapi-first health_app\n\nCreate the service in a custom directory:\n\n openapi-first health_app my-health-service\n\nList all available application templates:\n\n openapi-first --list\n\nThe CLI copies template files verbatim into the target directory.\nNo code is generated or modified beyond the copied scaffold.\n\n----------------------------------------------------------------------\nClient Usage Example\n----------------------------------------------------------------------\n\nThe same OpenAPI specification used by the server can be used to\nconstruct a strict, operationId-driven HTTP client.\n\nExample client call for the ``get_health`` operation:\n\n from openapi_first.loader import load_openapi\n from openapi_first.client import OpenAPIClient\n\n spec = load_openapi(\"openapi.yaml\")\n client = OpenAPIClient(spec)\n\n response = client.get_health()\n\n assert response.status_code == 200\n assert response.json() == {\"status\": \"ok\"}\n\nClient guarantees:\n- One callable per OpenAPI ``operationId``\n- No hardcoded URLs or HTTP methods in user code\n- Path and request parameters must match the OpenAPI specification\n- Invalid or incomplete OpenAPI specs fail at client construction time",
"members": {
"main": {
"name": "main",
"kind": "module",
"path": "openapi_first.templates.health_app.main",
"signature": null,
"docstring": "Application entry point for an OpenAPI-first FastAPI service.\n\nThis module constructs a FastAPI application exclusively from an\nOpenAPI specification and a handler namespace, without using\ndecorator-driven routing.\n\nAll HTTP routes, methods, and operation bindings are defined in the\nOpenAPI document referenced by ``openapi_path``. Python callables\ndefined in the ``routes`` module are bound to OpenAPI operations\nstrictly via ``operationId``.\n\nThis module contains no routing logic, request handling, or framework\nconfiguration beyond application assembly.\n\nDesign guarantees:\n- OpenAPI is the single source of truth\n- No undocumented routes can exist\n- Every OpenAPI operationId must resolve to exactly one handler\n- All contract violations fail at application startup\n\nThis file is intended to be used as the ASGI entry point.\n\nExample:\n uvicorn main:app",
"members": {
"OpenAPIFirstApp": {
"name": "OpenAPIFirstApp",
"kind": "class",
"path": "openapi_first.templates.health_app.main.OpenAPIFirstApp",
"signature": "<bound method Alias.signature of Alias('OpenAPIFirstApp', 'openapi_first.app.OpenAPIFirstApp')>",
"docstring": "FastAPI application enforcing OpenAPI-first design.\n\n`OpenAPIFirstApp` subclasses FastAPI and replaces manual route\nregistration with OpenAPI-driven binding. All routes are derived\nfrom the provided OpenAPI specification, and each operationId is\nmapped to a Python function in the supplied routes module.\n\nParameters\n----------\nopenapi_path : str\n Filesystem path to the OpenAPI 3.x specification file.\n This specification is treated as the authoritative API contract.\n\nroutes_module : module\n Python module containing handler functions whose names correspond\n exactly to OpenAPI operationId values.\n\n**fastapi_kwargs\n Additional keyword arguments passed directly to `fastapi.FastAPI`\n (e.g., title, version, middleware, lifespan handlers).\n\nRaises\n------\nOpenAPIFirstError\n If the OpenAPI specification is invalid, or if any declared\n operationId does not have a corresponding handler function.\n\nBehavior guarantees\n-------------------\n- No route can exist without an OpenAPI declaration.\n- No OpenAPI operation can exist without a handler.\n- Swagger UI and `/openapi.json` always reflect the provided spec.\n- Handler functions remain framework-agnostic and testable.\n\nExample\n-------\n>>> from openapi_first import OpenAPIFirstApp\n>>> import app.routes as routes\n>>>\n>>> app = OpenAPIFirstApp(\n... openapi_path=\"app/openapi.json\",\n... routes_module=routes,\n... title=\"Example Service\"\n... )",
"members": {
"openapi": {
"name": "openapi",
"kind": "attribute",
"path": "openapi_first.templates.health_app.main.OpenAPIFirstApp.openapi",
"signature": "<bound method Alias.signature of Alias('openapi', 'openapi_first.app.OpenAPIFirstApp.openapi')>",
"docstring": null
}
}
},
"routes": {
"name": "routes",
"kind": "alias",
"path": "openapi_first.templates.health_app.main.routes",
"signature": "<bound method Alias.signature of Alias('routes', 'routes')>",
"docstring": null
},
"app": {
"name": "app",
"kind": "attribute",
"path": "openapi_first.templates.health_app.main.app",
"signature": null,
"docstring": null
}
}
},
"routes": {
"name": "routes",
"kind": "module",
"path": "openapi_first.templates.health_app.routes",
"signature": null,
"docstring": "OpenAPI operation handlers.\n\nThis module defines pure Python callables that implement OpenAPI\noperations for this service. Functions in this module are bound to HTTP\nroutes exclusively via OpenAPI ``operationId`` values.\n\nNo routing decorators, HTTP metadata, or framework-specific logic\nshould appear here. All request/response semantics are defined in the\nOpenAPI specification.\n\nThis module serves solely as an operationId namespace.",
"members": {
"get_health": {
"name": "get_health",
"kind": "function",
"path": "openapi_first.templates.health_app.routes.get_health",
"signature": "<bound method Function.signature of Function('get_health', 16, 32)>",
"docstring": "Health check operation handler.\n\nThis function implements the OpenAPI operation identified by\n``operationId: get_health``.\n\nIt contains no routing metadata or framework-specific logic.\nRequest binding, HTTP method, and response semantics are defined\nexclusively by the OpenAPI specification.\n\nReturns\n-------\ndict\n A minimal liveness payload indicating service health."
}
}
}
}
},
"model_app": {
"name": "model_app",
"kind": "module",
"path": "openapi_first.templates.model_app",
"signature": null,
"docstring": "OpenAPI-first model-based CRUD application template.\n\nThis package contains a complete, minimal example of an OpenAPI-first\nCRUD service that uses explicit Pydantic domain models for request and\nresponse schemas.\n\nThe application is assembled exclusively from:\n- an OpenAPI specification (``openapi.yaml``)\n- a handler namespace implementing CRUD operations (``routes``)\n- Pydantic domain models (``models``)\n- an in-memory mock data store (``data``)\n\nAll HTTP routes, methods, schemas, and operation bindings are defined\nin the OpenAPI specification and enforced at application startup.\nNo decorator-driven routing or implicit framework behavior is used.\n\nThis template demonstrates:\n- operationId-driven server-side route binding\n- explicit request and response modeling with Pydantic\n- explicit HTTP status code control in handlers\n- operationId-driven client usage against the same OpenAPI contract\n- end-to-end validation using in-memory data and tests\n\n----------------------------------------------------------------------\nScaffolding via CLI\n----------------------------------------------------------------------\n\nCreate a new model-based CRUD example service using the bundled template:\n\n openapi-first model_app\n\nCreate the service in a custom directory:\n\n openapi-first model_app my-model-service\n\nList all available application templates:\n\n openapi-first --list\n\nThe CLI copies template files verbatim into the target directory.\nNo code is generated or modified beyond the copied scaffold.\n\n----------------------------------------------------------------------\nClient Usage Example\n----------------------------------------------------------------------\n\nThe same OpenAPI specification used by the server can be used to\nconstruct a strict, operationId-driven HTTP client.\n\nExample client calls for model-based CRUD operations:\n\n from openapi_first.loader import load_openapi\n from openapi_first.client import OpenAPIClient\n\n spec = load_openapi(\"openapi.yaml\")\n client = OpenAPIClient(spec)\n\n # List items\n response = client.list_items()\n\n # Get item by ID\n response = client.get_item(\n path_params={\"item_id\": 1}\n )\n\n # Create item\n response = client.create_item(\n body={\"name\": \"Orange\", \"price\": 0.8}\n )\n\n # Update item\n response = client.update_item(\n path_params={\"item_id\": 1},\n body={\"name\": \"Green Apple\", \"price\": 0.6},\n )\n\n # Delete item\n response = client.delete_item(\n path_params={\"item_id\": 1}\n )\n\nClient guarantees:\n- One callable per OpenAPI ``operationId``\n- No hardcoded URLs or HTTP methods in user code\n- Request and response payloads conform to Pydantic models\n- Invalid or incomplete OpenAPI specs fail at client construction time\n\n----------------------------------------------------------------------\nNon-Goals\n----------------------------------------------------------------------\n\nThis template is intentionally minimal and is NOT:\n- production-ready\n- persistent or concurrency-safe\n- a reference architecture for data storage\n\nIt exists solely as a copyable example for learning, testing, and\nbootstrapping OpenAPI-first services.\n\nThis package is not part of the ``openapi_first`` library API surface.",
"members": {
"data": {
"name": "data",
"kind": "module",
"path": "openapi_first.templates.model_app.data",
"signature": null,
"docstring": "In-memory data store using Pydantic models.\n\nThis module is NOT thread-safe and is intended for demos and scaffolds only.\nThis module provides a minimal, process-local data store for the\nmodel-based CRUD example application. It stores and returns domain\nobjects defined using Pydantic models and is intended solely for\ndemonstration and scaffolding purposes.\n\nThe implementation intentionally avoids:\n- persistence\n- concurrency guarantees\n- transactional semantics\n- validation beyond what Pydantic provides\n\nIt is not part of the ``openapi_first`` library API surface.",
"members": {
"Dict": {
"name": "Dict",
"kind": "alias",
"path": "openapi_first.templates.model_app.data.Dict",
"signature": "<bound method Alias.signature of Alias('Dict', 'typing.Dict')>",
"docstring": null
},
"Item": {
"name": "Item",
"kind": "alias",
"path": "openapi_first.templates.model_app.data.Item",
"signature": "<bound method Alias.signature of Alias('Item', 'models.Item')>",
"docstring": null
},
"ItemCreate": {
"name": "ItemCreate",
"kind": "alias",
"path": "openapi_first.templates.model_app.data.ItemCreate",
"signature": "<bound method Alias.signature of Alias('ItemCreate', 'models.ItemCreate')>",
"docstring": null
},
"list_items": {
"name": "list_items",
"kind": "function",
"path": "openapi_first.templates.model_app.data.list_items",
"signature": "<bound method Function.signature of Function('list_items', 34, 43)>",
"docstring": "Return all items in the data store.\n\nReturns\n-------\nlist[Item]\n A list of item domain objects."
},
"get_item": {
"name": "get_item",
"kind": "function",
"path": "openapi_first.templates.model_app.data.get_item",
"signature": "<bound method Function.signature of Function('get_item', 46, 65)>",
"docstring": "Retrieve a single item by ID.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to retrieve.\n\nReturns\n-------\nItem\n The requested item.\n\nRaises\n------\nKeyError\n If the item does not exist."
},
"create_item": {
"name": "create_item",
"kind": "function",
"path": "openapi_first.templates.model_app.data.create_item",
"signature": "<bound method Function.signature of Function('create_item', 68, 89)>",
"docstring": "Create a new item in the data store.\n\nA new identifier is assigned automatically. No additional validation\nis performed beyond Pydantic model validation.\n\nParameters\n----------\npayload : ItemCreate\n Data required to create a new item.\n\nReturns\n-------\nItem\n The newly created item."
},
"update_item": {
"name": "update_item",
"kind": "function",
"path": "openapi_first.templates.model_app.data.update_item",
"signature": "<bound method Function.signature of Function('update_item', 92, 120)>",
"docstring": "Replace an existing item in the data store.\n\nThis function performs a full replacement of the stored item.\nPartial updates are not supported.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to update.\npayload : ItemCreate\n New item data.\n\nReturns\n-------\nItem\n The updated item.\n\nRaises\n------\nKeyError\n If the item does not exist."
},
"delete_item": {
"name": "delete_item",
"kind": "function",
"path": "openapi_first.templates.model_app.data.delete_item",
"signature": "<bound method Function.signature of Function('delete_item', 123, 137)>",
"docstring": "Remove an item from the data store.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to delete.\n\nRaises\n------\nKeyError\n If the item does not exist."
}
}
},
"main": {
"name": "main",
"kind": "module",
"path": "openapi_first.templates.model_app.main",
"signature": null,
"docstring": "Application entry point for an OpenAPI-first model-based CRUD example service.\n\nThis module constructs a FastAPI application exclusively from an\nOpenAPI specification and a handler namespace, without using\ndecorator-driven routing.\n\nAll HTTP routes, methods, request/response schemas, and operation\nbindings are defined in the OpenAPI document referenced by\n``openapi_path``. Python callables defined in the ``routes`` module are\nbound to OpenAPI operations strictly via ``operationId``.\n\nThis module contains no routing logic, persistence concerns, or\nframework configuration beyond application assembly.\n\nDesign guarantees:\n- OpenAPI is the single source of truth\n- No undocumented routes can exist\n- Every OpenAPI operationId must resolve to exactly one handler\n- All contract violations fail at application startup\n\nThis file is intended to be used as the ASGI entry point.\n\nExample:\n uvicorn main:app",
"members": {
"OpenAPIFirstApp": {
"name": "OpenAPIFirstApp",
"kind": "class",
"path": "openapi_first.templates.model_app.main.OpenAPIFirstApp",
"signature": "<bound method Alias.signature of Alias('OpenAPIFirstApp', 'openapi_first.app.OpenAPIFirstApp')>",
"docstring": "FastAPI application enforcing OpenAPI-first design.\n\n`OpenAPIFirstApp` subclasses FastAPI and replaces manual route\nregistration with OpenAPI-driven binding. All routes are derived\nfrom the provided OpenAPI specification, and each operationId is\nmapped to a Python function in the supplied routes module.\n\nParameters\n----------\nopenapi_path : str\n Filesystem path to the OpenAPI 3.x specification file.\n This specification is treated as the authoritative API contract.\n\nroutes_module : module\n Python module containing handler functions whose names correspond\n exactly to OpenAPI operationId values.\n\n**fastapi_kwargs\n Additional keyword arguments passed directly to `fastapi.FastAPI`\n (e.g., title, version, middleware, lifespan handlers).\n\nRaises\n------\nOpenAPIFirstError\n If the OpenAPI specification is invalid, or if any declared\n operationId does not have a corresponding handler function.\n\nBehavior guarantees\n-------------------\n- No route can exist without an OpenAPI declaration.\n- No OpenAPI operation can exist without a handler.\n- Swagger UI and `/openapi.json` always reflect the provided spec.\n- Handler functions remain framework-agnostic and testable.\n\nExample\n-------\n>>> from openapi_first import OpenAPIFirstApp\n>>> import app.routes as routes\n>>>\n>>> app = OpenAPIFirstApp(\n... openapi_path=\"app/openapi.json\",\n... routes_module=routes,\n... title=\"Example Service\"\n... )",
"members": {
"openapi": {
"name": "openapi",
"kind": "attribute",
"path": "openapi_first.templates.model_app.main.OpenAPIFirstApp.openapi",
"signature": "<bound method Alias.signature of Alias('openapi', 'openapi_first.app.OpenAPIFirstApp.openapi')>",
"docstring": null
}
}
},
"routes": {
"name": "routes",
"kind": "alias",
"path": "openapi_first.templates.model_app.main.routes",
"signature": "<bound method Alias.signature of Alias('routes', 'routes')>",
"docstring": null
},
"app": {
"name": "app",
"kind": "attribute",
"path": "openapi_first.templates.model_app.main.app",
"signature": null,
"docstring": null
}
}
},
"models": {
"name": "models",
"kind": "module",
"path": "openapi_first.templates.model_app.models",
"signature": null,
"docstring": "Pydantic domain models for the CRUD example.\n\nThis module defines Pydantic models that represent the domain entities\nused by the service. These models are referenced by the OpenAPI\nspecification for request and response schemas.\n\nThe models are declarative and framework-agnostic. They contain no\npersistence logic, validation beyond type constraints, or business\nbehavior.\n\nThis module is not part of the ``openapi_first`` library API surface.\nIt exists solely to support the example application template.",
"members": {
"BaseModel": {
"name": "BaseModel",
"kind": "alias",
"path": "openapi_first.templates.model_app.models.BaseModel",
"signature": "<bound method Alias.signature of Alias('BaseModel', 'pydantic.BaseModel')>",
"docstring": null
},
"ItemBase": {
"name": "ItemBase",
"kind": "class",
"path": "openapi_first.templates.model_app.models.ItemBase",
"signature": "<bound method Class.signature of Class('ItemBase', 19, 27)>",
"docstring": "Base domain model for an item.\n\nDefines fields common to all item representations.",
"members": {
"name": {
"name": "name",
"kind": "attribute",
"path": "openapi_first.templates.model_app.models.ItemBase.name",
"signature": null,
"docstring": null
},
"price": {
"name": "price",
"kind": "attribute",
"path": "openapi_first.templates.model_app.models.ItemBase.price",
"signature": null,
"docstring": null
}
}
},
"ItemCreate": {
"name": "ItemCreate",
"kind": "class",
"path": "openapi_first.templates.model_app.models.ItemCreate",
"signature": "<bound method Class.signature of Class('ItemCreate', 30, 39)>",
"docstring": "Domain model for item creation requests.\n\nThis model is used for request bodies when creating new items.\nIt intentionally excludes the ``id`` field, which is assigned\nby the service."
},
"Item": {
"name": "Item",
"kind": "class",
"path": "openapi_first.templates.model_app.models.Item",
"signature": "<bound method Class.signature of Class('Item', 42, 50)>",
"docstring": "Domain model for a persisted item.\n\nThis model represents the full item state returned in responses,\nincluding the server-assigned identifier.",
"members": {
"id": {
"name": "id",
"kind": "attribute",
"path": "openapi_first.templates.model_app.models.Item.id",
"signature": null,
"docstring": null
}
}
}
}
},
"routes": {
"name": "routes",
"kind": "module",
"path": "openapi_first.templates.model_app.routes",
"signature": null,
"docstring": "CRUD route handlers bound via OpenAPI operationId.\n\nThis module defines OpenAPI-bound operation handlers for a model-based\nCRUD service. Functions in this module are bound to HTTP routes\nexclusively via OpenAPI ``operationId`` values.\n\nHandlers explicitly control HTTP response status codes to ensure runtime\nbehavior matches the OpenAPI contract. Domain models defined using\nPydantic are used for request and response payloads.\n\nNo routing decorators, path definitions, or implicit framework behavior\nappear in this module. All routing, HTTP methods, and schemas are defined\nin the OpenAPI specification.",
"members": {
"Response": {
"name": "Response",
"kind": "alias",
"path": "openapi_first.templates.model_app.routes.Response",
"signature": "<bound method Alias.signature of Alias('Response', 'fastapi.Response')>",
"docstring": null
},
"HTTPException": {
"name": "HTTPException",
"kind": "alias",
"path": "openapi_first.templates.model_app.routes.HTTPException",
"signature": "<bound method Alias.signature of Alias('HTTPException', 'fastapi.HTTPException')>",
"docstring": null
},
"ItemCreate": {
"name": "ItemCreate",
"kind": "alias",
"path": "openapi_first.templates.model_app.routes.ItemCreate",
"signature": "<bound method Alias.signature of Alias('ItemCreate', 'models.ItemCreate')>",
"docstring": null
},
"list_items": {
"name": "list_items",
"kind": "function",
"path": "openapi_first.templates.model_app.routes.list_items",
"signature": "<bound method Function.signature of Function('list_items', 29, 41)>",
"docstring": "List all items.\n\nImplements the OpenAPI operation identified by\n``operationId: list_items``.\n\nReturns\n-------\nlist[Item]\n A list of item domain objects."
},
"get_item": {
"name": "get_item",
"kind": "function",
"path": "openapi_first.templates.model_app.routes.get_item",
"signature": "<bound method Function.signature of Function('get_item', 44, 69)>",
"docstring": "Retrieve a single item by ID.\n\nImplements the OpenAPI operation identified by\n``operationId: get_item``.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to retrieve.\n\nReturns\n-------\nItem\n The requested item.\n\nRaises\n------\nHTTPException\n 404 if the item does not exist."
},
"create_item": {
"name": "create_item",
"kind": "function",
"path": "openapi_first.templates.model_app.routes.create_item",
"signature": "<bound method Function.signature of Function('create_item', 72, 93)>",
"docstring": "Create a new item.\n\nImplements the OpenAPI operation identified by\n``operationId: create_item``.\n\nParameters\n----------\npayload : ItemCreate\n Request body describing the item to create.\nresponse : fastapi.Response\n Response object used to set the HTTP status code.\n\nReturns\n-------\nItem\n The newly created item."
},
"update_item": {
"name": "update_item",
"kind": "function",
"path": "openapi_first.templates.model_app.routes.update_item",
"signature": "<bound method Function.signature of Function('update_item', 96, 123)>",
"docstring": "Update an existing item.\n\nImplements the OpenAPI operation identified by\n``operationId: update_item``.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to update.\npayload : ItemCreate\n New item data.\n\nReturns\n-------\nItem\n The updated item.\n\nRaises\n------\nHTTPException\n 404 if the item does not exist."
},
"delete_item": {
"name": "delete_item",
"kind": "function",
"path": "openapi_first.templates.model_app.routes.delete_item",
"signature": "<bound method Function.signature of Function('delete_item', 126, 156)>",
"docstring": "Delete an existing item.\n\nImplements the OpenAPI operation identified by\n``operationId: delete_item``.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to delete.\nresponse : fastapi.Response\n Response object used to set the HTTP status code.\n\nReturns\n-------\nNone\n No content.\n\nRaises\n------\nHTTPException\n 404 if the item does not exist."
}
}
},
"test_model_app": {
"name": "test_model_app",
"kind": "module",
"path": "openapi_first.templates.model_app.test_model_app",
"signature": null,
"docstring": "End-to-end tests for the OpenAPI-first model CRUD example app.\n\nThese tests validate that all CRUD operations behave correctly\nagainst the in-memory mock data store using Pydantic models.\n- OpenAPI specification loading\n- OperationId-driven route binding on the server\n- OperationId-driven client invocation\n- Pydantic model-based request and response handling\n\nAll CRUD operations are exercised against an in-memory mock data store\nbacked by Pydantic domain models.\n\nThe tests assume:\n- OpenAPI-first route binding\n- Pydantic model validation\n- In-memory storage (no persistence guarantees)\n- Deterministic behavior in a single process",
"members": {
"TestClient": {
"name": "TestClient",
"kind": "alias",
"path": "openapi_first.templates.model_app.test_model_app.TestClient",
"signature": "<bound method Alias.signature of Alias('TestClient', 'fastapi.testclient.TestClient')>",
"docstring": null
},
"app": {
"name": "app",
"kind": "alias",
"path": "openapi_first.templates.model_app.test_model_app.app",
"signature": "<bound method Alias.signature of Alias('app', 'main.app')>",
"docstring": null
},
"load_openapi": {
"name": "load_openapi",
"kind": "function",
"path": "openapi_first.templates.model_app.test_model_app.load_openapi",
"signature": "<bound method Alias.signature of Alias('load_openapi', 'openapi_first.loader.load_openapi')>",
"docstring": "Load and validate an OpenAPI 3.x specification from disk.\n\nThe specification is parsed based on file extension and validated\nusing a strict OpenAPI schema validator. Any error results in an\nimmediate exception, preventing application startup.\n\nParameters\n----------\npath : str or pathlib.Path\n Filesystem path to an OpenAPI specification file.\n Supported extensions:\n - `.json`\n - `.yaml`\n - `.yml`\n\nReturns\n-------\ndict\n Parsed and validated OpenAPI specification.\n\nRaises\n------\nOpenAPISpecLoadError\n If the file does not exist, cannot be parsed, or fails\n OpenAPI schema validation."
},
"OpenAPIClient": {
"name": "OpenAPIClient",
"kind": "class",
"path": "openapi_first.templates.model_app.test_model_app.OpenAPIClient",
"signature": "<bound method Alias.signature of Alias('OpenAPIClient', 'openapi_first.client.OpenAPIClient')>",
"docstring": "OpenAPI-first HTTP client (httpx-based).\n\n- One callable per operationId\n- Explicit parameters (path, query, headers, body)\n- No implicit schema inference or mutation",
"members": {
"spec": {
"name": "spec",
"kind": "attribute",
"path": "openapi_first.templates.model_app.test_model_app.OpenAPIClient.spec",
"signature": "<bound method Alias.signature of Alias('spec', 'openapi_first.client.OpenAPIClient.spec')>",
"docstring": null
},
"base_url": {
"name": "base_url",
"kind": "attribute",
"path": "openapi_first.templates.model_app.test_model_app.OpenAPIClient.base_url",
"signature": "<bound method Alias.signature of Alias('base_url', 'openapi_first.client.OpenAPIClient.base_url')>",
"docstring": null
},
"client": {
"name": "client",
"kind": "attribute",
"path": "openapi_first.templates.model_app.test_model_app.OpenAPIClient.client",
"signature": "<bound method Alias.signature of Alias('client', 'openapi_first.client.OpenAPIClient.client')>",
"docstring": null
},
"operations": {
"name": "operations",
"kind": "function",
"path": "openapi_first.templates.model_app.test_model_app.OpenAPIClient.operations",
"signature": "<bound method Alias.signature of Alias('operations', 'openapi_first.client.OpenAPIClient.operations')>",
"docstring": null
}
}
},
"client": {
"name": "client",
"kind": "attribute",
"path": "openapi_first.templates.model_app.test_model_app.client",
"signature": null,
"docstring": null
},
"spec": {
"name": "spec",
"kind": "attribute",
"path": "openapi_first.templates.model_app.test_model_app.spec",
"signature": null,
"docstring": null
},
"test_list_items_initial": {
"name": "test_list_items_initial",
"kind": "function",
"path": "openapi_first.templates.model_app.test_model_app.test_list_items_initial",
"signature": "<bound method Function.signature of Function('test_list_items_initial', 37, 48)>",
"docstring": "Initial items should be present."
},
"test_get_item": {
"name": "test_get_item",
"kind": "function",
"path": "openapi_first.templates.model_app.test_model_app.test_get_item",
"signature": "<bound method Function.signature of Function('test_get_item', 51, 61)>",
"docstring": "Existing item should be retrievable by ID."
},
"test_create_item": {
"name": "test_create_item",
"kind": "function",
"path": "openapi_first.templates.model_app.test_model_app.test_create_item",
"signature": "<bound method Function.signature of Function('test_create_item', 64, 84)>",
"docstring": "Creating a new item should return the created entity."
},
"test_update_item": {
"name": "test_update_item",
"kind": "function",
"path": "openapi_first.templates.model_app.test_model_app.test_update_item",
"signature": "<bound method Function.signature of Function('test_update_item', 87, 111)>",
"docstring": "Updating an item should replace its values."
},
"test_delete_item": {
"name": "test_delete_item",
"kind": "function",
"path": "openapi_first.templates.model_app.test_model_app.test_delete_item",
"signature": "<bound method Function.signature of Function('test_delete_item', 114, 124)>",
"docstring": "Deleting an item should remove it from the store."
}
}
}
}
}
}
}
}

View File

@@ -0,0 +1,65 @@
{
"module": "openapi_first.templates.model_app.data",
"content": {
"path": "openapi_first.templates.model_app.data",
"docstring": "In-memory data store using Pydantic models.\n\nThis module is NOT thread-safe and is intended for demos and scaffolds only.\nThis module provides a minimal, process-local data store for the\nmodel-based CRUD example application. It stores and returns domain\nobjects defined using Pydantic models and is intended solely for\ndemonstration and scaffolding purposes.\n\nThe implementation intentionally avoids:\n- persistence\n- concurrency guarantees\n- transactional semantics\n- validation beyond what Pydantic provides\n\nIt is not part of the ``openapi_first`` library API surface.",
"objects": {
"Dict": {
"name": "Dict",
"kind": "alias",
"path": "openapi_first.templates.model_app.data.Dict",
"signature": "<bound method Alias.signature of Alias('Dict', 'typing.Dict')>",
"docstring": null
},
"Item": {
"name": "Item",
"kind": "alias",
"path": "openapi_first.templates.model_app.data.Item",
"signature": "<bound method Alias.signature of Alias('Item', 'models.Item')>",
"docstring": null
},
"ItemCreate": {
"name": "ItemCreate",
"kind": "alias",
"path": "openapi_first.templates.model_app.data.ItemCreate",
"signature": "<bound method Alias.signature of Alias('ItemCreate', 'models.ItemCreate')>",
"docstring": null
},
"list_items": {
"name": "list_items",
"kind": "function",
"path": "openapi_first.templates.model_app.data.list_items",
"signature": "<bound method Function.signature of Function('list_items', 34, 43)>",
"docstring": "Return all items in the data store.\n\nReturns\n-------\nlist[Item]\n A list of item domain objects."
},
"get_item": {
"name": "get_item",
"kind": "function",
"path": "openapi_first.templates.model_app.data.get_item",
"signature": "<bound method Function.signature of Function('get_item', 46, 65)>",
"docstring": "Retrieve a single item by ID.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to retrieve.\n\nReturns\n-------\nItem\n The requested item.\n\nRaises\n------\nKeyError\n If the item does not exist."
},
"create_item": {
"name": "create_item",
"kind": "function",
"path": "openapi_first.templates.model_app.data.create_item",
"signature": "<bound method Function.signature of Function('create_item', 68, 89)>",
"docstring": "Create a new item in the data store.\n\nA new identifier is assigned automatically. No additional validation\nis performed beyond Pydantic model validation.\n\nParameters\n----------\npayload : ItemCreate\n Data required to create a new item.\n\nReturns\n-------\nItem\n The newly created item."
},
"update_item": {
"name": "update_item",
"kind": "function",
"path": "openapi_first.templates.model_app.data.update_item",
"signature": "<bound method Function.signature of Function('update_item', 92, 120)>",
"docstring": "Replace an existing item in the data store.\n\nThis function performs a full replacement of the stored item.\nPartial updates are not supported.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to update.\npayload : ItemCreate\n New item data.\n\nReturns\n-------\nItem\n The updated item.\n\nRaises\n------\nKeyError\n If the item does not exist."
},
"delete_item": {
"name": "delete_item",
"kind": "function",
"path": "openapi_first.templates.model_app.data.delete_item",
"signature": "<bound method Function.signature of Function('delete_item', 123, 137)>",
"docstring": "Remove an item from the data store.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to delete.\n\nRaises\n------\nKeyError\n If the item does not exist."
}
}
}
}

View File

@@ -0,0 +1,356 @@
{
"module": "openapi_first.templates.model_app",
"content": {
"path": "openapi_first.templates.model_app",
"docstring": "OpenAPI-first model-based CRUD application template.\n\nThis package contains a complete, minimal example of an OpenAPI-first\nCRUD service that uses explicit Pydantic domain models for request and\nresponse schemas.\n\nThe application is assembled exclusively from:\n- an OpenAPI specification (``openapi.yaml``)\n- a handler namespace implementing CRUD operations (``routes``)\n- Pydantic domain models (``models``)\n- an in-memory mock data store (``data``)\n\nAll HTTP routes, methods, schemas, and operation bindings are defined\nin the OpenAPI specification and enforced at application startup.\nNo decorator-driven routing or implicit framework behavior is used.\n\nThis template demonstrates:\n- operationId-driven server-side route binding\n- explicit request and response modeling with Pydantic\n- explicit HTTP status code control in handlers\n- operationId-driven client usage against the same OpenAPI contract\n- end-to-end validation using in-memory data and tests\n\n----------------------------------------------------------------------\nScaffolding via CLI\n----------------------------------------------------------------------\n\nCreate a new model-based CRUD example service using the bundled template:\n\n openapi-first model_app\n\nCreate the service in a custom directory:\n\n openapi-first model_app my-model-service\n\nList all available application templates:\n\n openapi-first --list\n\nThe CLI copies template files verbatim into the target directory.\nNo code is generated or modified beyond the copied scaffold.\n\n----------------------------------------------------------------------\nClient Usage Example\n----------------------------------------------------------------------\n\nThe same OpenAPI specification used by the server can be used to\nconstruct a strict, operationId-driven HTTP client.\n\nExample client calls for model-based CRUD operations:\n\n from openapi_first.loader import load_openapi\n from openapi_first.client import OpenAPIClient\n\n spec = load_openapi(\"openapi.yaml\")\n client = OpenAPIClient(spec)\n\n # List items\n response = client.list_items()\n\n # Get item by ID\n response = client.get_item(\n path_params={\"item_id\": 1}\n )\n\n # Create item\n response = client.create_item(\n body={\"name\": \"Orange\", \"price\": 0.8}\n )\n\n # Update item\n response = client.update_item(\n path_params={\"item_id\": 1},\n body={\"name\": \"Green Apple\", \"price\": 0.6},\n )\n\n # Delete item\n response = client.delete_item(\n path_params={\"item_id\": 1}\n )\n\nClient guarantees:\n- One callable per OpenAPI ``operationId``\n- No hardcoded URLs or HTTP methods in user code\n- Request and response payloads conform to Pydantic models\n- Invalid or incomplete OpenAPI specs fail at client construction time\n\n----------------------------------------------------------------------\nNon-Goals\n----------------------------------------------------------------------\n\nThis template is intentionally minimal and is NOT:\n- production-ready\n- persistent or concurrency-safe\n- a reference architecture for data storage\n\nIt exists solely as a copyable example for learning, testing, and\nbootstrapping OpenAPI-first services.\n\nThis package is not part of the ``openapi_first`` library API surface.",
"objects": {
"data": {
"name": "data",
"kind": "module",
"path": "openapi_first.templates.model_app.data",
"signature": null,
"docstring": "In-memory data store using Pydantic models.\n\nThis module is NOT thread-safe and is intended for demos and scaffolds only.\nThis module provides a minimal, process-local data store for the\nmodel-based CRUD example application. It stores and returns domain\nobjects defined using Pydantic models and is intended solely for\ndemonstration and scaffolding purposes.\n\nThe implementation intentionally avoids:\n- persistence\n- concurrency guarantees\n- transactional semantics\n- validation beyond what Pydantic provides\n\nIt is not part of the ``openapi_first`` library API surface.",
"members": {
"Dict": {
"name": "Dict",
"kind": "alias",
"path": "openapi_first.templates.model_app.data.Dict",
"signature": "<bound method Alias.signature of Alias('Dict', 'typing.Dict')>",
"docstring": null
},
"Item": {
"name": "Item",
"kind": "alias",
"path": "openapi_first.templates.model_app.data.Item",
"signature": "<bound method Alias.signature of Alias('Item', 'models.Item')>",
"docstring": null
},
"ItemCreate": {
"name": "ItemCreate",
"kind": "alias",
"path": "openapi_first.templates.model_app.data.ItemCreate",
"signature": "<bound method Alias.signature of Alias('ItemCreate', 'models.ItemCreate')>",
"docstring": null
},
"list_items": {
"name": "list_items",
"kind": "function",
"path": "openapi_first.templates.model_app.data.list_items",
"signature": "<bound method Function.signature of Function('list_items', 34, 43)>",
"docstring": "Return all items in the data store.\n\nReturns\n-------\nlist[Item]\n A list of item domain objects."
},
"get_item": {
"name": "get_item",
"kind": "function",
"path": "openapi_first.templates.model_app.data.get_item",
"signature": "<bound method Function.signature of Function('get_item', 46, 65)>",
"docstring": "Retrieve a single item by ID.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to retrieve.\n\nReturns\n-------\nItem\n The requested item.\n\nRaises\n------\nKeyError\n If the item does not exist."
},
"create_item": {
"name": "create_item",
"kind": "function",
"path": "openapi_first.templates.model_app.data.create_item",
"signature": "<bound method Function.signature of Function('create_item', 68, 89)>",
"docstring": "Create a new item in the data store.\n\nA new identifier is assigned automatically. No additional validation\nis performed beyond Pydantic model validation.\n\nParameters\n----------\npayload : ItemCreate\n Data required to create a new item.\n\nReturns\n-------\nItem\n The newly created item."
},
"update_item": {
"name": "update_item",
"kind": "function",
"path": "openapi_first.templates.model_app.data.update_item",
"signature": "<bound method Function.signature of Function('update_item', 92, 120)>",
"docstring": "Replace an existing item in the data store.\n\nThis function performs a full replacement of the stored item.\nPartial updates are not supported.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to update.\npayload : ItemCreate\n New item data.\n\nReturns\n-------\nItem\n The updated item.\n\nRaises\n------\nKeyError\n If the item does not exist."
},
"delete_item": {
"name": "delete_item",
"kind": "function",
"path": "openapi_first.templates.model_app.data.delete_item",
"signature": "<bound method Function.signature of Function('delete_item', 123, 137)>",
"docstring": "Remove an item from the data store.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to delete.\n\nRaises\n------\nKeyError\n If the item does not exist."
}
}
},
"main": {
"name": "main",
"kind": "module",
"path": "openapi_first.templates.model_app.main",
"signature": null,
"docstring": "Application entry point for an OpenAPI-first model-based CRUD example service.\n\nThis module constructs a FastAPI application exclusively from an\nOpenAPI specification and a handler namespace, without using\ndecorator-driven routing.\n\nAll HTTP routes, methods, request/response schemas, and operation\nbindings are defined in the OpenAPI document referenced by\n``openapi_path``. Python callables defined in the ``routes`` module are\nbound to OpenAPI operations strictly via ``operationId``.\n\nThis module contains no routing logic, persistence concerns, or\nframework configuration beyond application assembly.\n\nDesign guarantees:\n- OpenAPI is the single source of truth\n- No undocumented routes can exist\n- Every OpenAPI operationId must resolve to exactly one handler\n- All contract violations fail at application startup\n\nThis file is intended to be used as the ASGI entry point.\n\nExample:\n uvicorn main:app",
"members": {
"OpenAPIFirstApp": {
"name": "OpenAPIFirstApp",
"kind": "class",
"path": "openapi_first.templates.model_app.main.OpenAPIFirstApp",
"signature": "<bound method Alias.signature of Alias('OpenAPIFirstApp', 'openapi_first.app.OpenAPIFirstApp')>",
"docstring": "FastAPI application enforcing OpenAPI-first design.\n\n`OpenAPIFirstApp` subclasses FastAPI and replaces manual route\nregistration with OpenAPI-driven binding. All routes are derived\nfrom the provided OpenAPI specification, and each operationId is\nmapped to a Python function in the supplied routes module.\n\nParameters\n----------\nopenapi_path : str\n Filesystem path to the OpenAPI 3.x specification file.\n This specification is treated as the authoritative API contract.\n\nroutes_module : module\n Python module containing handler functions whose names correspond\n exactly to OpenAPI operationId values.\n\n**fastapi_kwargs\n Additional keyword arguments passed directly to `fastapi.FastAPI`\n (e.g., title, version, middleware, lifespan handlers).\n\nRaises\n------\nOpenAPIFirstError\n If the OpenAPI specification is invalid, or if any declared\n operationId does not have a corresponding handler function.\n\nBehavior guarantees\n-------------------\n- No route can exist without an OpenAPI declaration.\n- No OpenAPI operation can exist without a handler.\n- Swagger UI and `/openapi.json` always reflect the provided spec.\n- Handler functions remain framework-agnostic and testable.\n\nExample\n-------\n>>> from openapi_first import OpenAPIFirstApp\n>>> import app.routes as routes\n>>>\n>>> app = OpenAPIFirstApp(\n... openapi_path=\"app/openapi.json\",\n... routes_module=routes,\n... title=\"Example Service\"\n... )",
"members": {
"openapi": {
"name": "openapi",
"kind": "attribute",
"path": "openapi_first.templates.model_app.main.OpenAPIFirstApp.openapi",
"signature": "<bound method Alias.signature of Alias('openapi', 'openapi_first.app.OpenAPIFirstApp.openapi')>",
"docstring": null
}
}
},
"routes": {
"name": "routes",
"kind": "alias",
"path": "openapi_first.templates.model_app.main.routes",
"signature": "<bound method Alias.signature of Alias('routes', 'routes')>",
"docstring": null
},
"app": {
"name": "app",
"kind": "attribute",
"path": "openapi_first.templates.model_app.main.app",
"signature": null,
"docstring": null
}
}
},
"models": {
"name": "models",
"kind": "module",
"path": "openapi_first.templates.model_app.models",
"signature": null,
"docstring": "Pydantic domain models for the CRUD example.\n\nThis module defines Pydantic models that represent the domain entities\nused by the service. These models are referenced by the OpenAPI\nspecification for request and response schemas.\n\nThe models are declarative and framework-agnostic. They contain no\npersistence logic, validation beyond type constraints, or business\nbehavior.\n\nThis module is not part of the ``openapi_first`` library API surface.\nIt exists solely to support the example application template.",
"members": {
"BaseModel": {
"name": "BaseModel",
"kind": "alias",
"path": "openapi_first.templates.model_app.models.BaseModel",
"signature": "<bound method Alias.signature of Alias('BaseModel', 'pydantic.BaseModel')>",
"docstring": null
},
"ItemBase": {
"name": "ItemBase",
"kind": "class",
"path": "openapi_first.templates.model_app.models.ItemBase",
"signature": "<bound method Class.signature of Class('ItemBase', 19, 27)>",
"docstring": "Base domain model for an item.\n\nDefines fields common to all item representations.",
"members": {
"name": {
"name": "name",
"kind": "attribute",
"path": "openapi_first.templates.model_app.models.ItemBase.name",
"signature": null,
"docstring": null
},
"price": {
"name": "price",
"kind": "attribute",
"path": "openapi_first.templates.model_app.models.ItemBase.price",
"signature": null,
"docstring": null
}
}
},
"ItemCreate": {
"name": "ItemCreate",
"kind": "class",
"path": "openapi_first.templates.model_app.models.ItemCreate",
"signature": "<bound method Class.signature of Class('ItemCreate', 30, 39)>",
"docstring": "Domain model for item creation requests.\n\nThis model is used for request bodies when creating new items.\nIt intentionally excludes the ``id`` field, which is assigned\nby the service."
},
"Item": {
"name": "Item",
"kind": "class",
"path": "openapi_first.templates.model_app.models.Item",
"signature": "<bound method Class.signature of Class('Item', 42, 50)>",
"docstring": "Domain model for a persisted item.\n\nThis model represents the full item state returned in responses,\nincluding the server-assigned identifier.",
"members": {
"id": {
"name": "id",
"kind": "attribute",
"path": "openapi_first.templates.model_app.models.Item.id",
"signature": null,
"docstring": null
}
}
}
}
},
"routes": {
"name": "routes",
"kind": "module",
"path": "openapi_first.templates.model_app.routes",
"signature": null,
"docstring": "CRUD route handlers bound via OpenAPI operationId.\n\nThis module defines OpenAPI-bound operation handlers for a model-based\nCRUD service. Functions in this module are bound to HTTP routes\nexclusively via OpenAPI ``operationId`` values.\n\nHandlers explicitly control HTTP response status codes to ensure runtime\nbehavior matches the OpenAPI contract. Domain models defined using\nPydantic are used for request and response payloads.\n\nNo routing decorators, path definitions, or implicit framework behavior\nappear in this module. All routing, HTTP methods, and schemas are defined\nin the OpenAPI specification.",
"members": {
"Response": {
"name": "Response",
"kind": "alias",
"path": "openapi_first.templates.model_app.routes.Response",
"signature": "<bound method Alias.signature of Alias('Response', 'fastapi.Response')>",
"docstring": null
},
"HTTPException": {
"name": "HTTPException",
"kind": "alias",
"path": "openapi_first.templates.model_app.routes.HTTPException",
"signature": "<bound method Alias.signature of Alias('HTTPException', 'fastapi.HTTPException')>",
"docstring": null
},
"ItemCreate": {
"name": "ItemCreate",
"kind": "alias",
"path": "openapi_first.templates.model_app.routes.ItemCreate",
"signature": "<bound method Alias.signature of Alias('ItemCreate', 'models.ItemCreate')>",
"docstring": null
},
"list_items": {
"name": "list_items",
"kind": "function",
"path": "openapi_first.templates.model_app.routes.list_items",
"signature": "<bound method Function.signature of Function('list_items', 29, 41)>",
"docstring": "List all items.\n\nImplements the OpenAPI operation identified by\n``operationId: list_items``.\n\nReturns\n-------\nlist[Item]\n A list of item domain objects."
},
"get_item": {
"name": "get_item",
"kind": "function",
"path": "openapi_first.templates.model_app.routes.get_item",
"signature": "<bound method Function.signature of Function('get_item', 44, 69)>",
"docstring": "Retrieve a single item by ID.\n\nImplements the OpenAPI operation identified by\n``operationId: get_item``.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to retrieve.\n\nReturns\n-------\nItem\n The requested item.\n\nRaises\n------\nHTTPException\n 404 if the item does not exist."
},
"create_item": {
"name": "create_item",
"kind": "function",
"path": "openapi_first.templates.model_app.routes.create_item",
"signature": "<bound method Function.signature of Function('create_item', 72, 93)>",
"docstring": "Create a new item.\n\nImplements the OpenAPI operation identified by\n``operationId: create_item``.\n\nParameters\n----------\npayload : ItemCreate\n Request body describing the item to create.\nresponse : fastapi.Response\n Response object used to set the HTTP status code.\n\nReturns\n-------\nItem\n The newly created item."
},
"update_item": {
"name": "update_item",
"kind": "function",
"path": "openapi_first.templates.model_app.routes.update_item",
"signature": "<bound method Function.signature of Function('update_item', 96, 123)>",
"docstring": "Update an existing item.\n\nImplements the OpenAPI operation identified by\n``operationId: update_item``.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to update.\npayload : ItemCreate\n New item data.\n\nReturns\n-------\nItem\n The updated item.\n\nRaises\n------\nHTTPException\n 404 if the item does not exist."
},
"delete_item": {
"name": "delete_item",
"kind": "function",
"path": "openapi_first.templates.model_app.routes.delete_item",
"signature": "<bound method Function.signature of Function('delete_item', 126, 156)>",
"docstring": "Delete an existing item.\n\nImplements the OpenAPI operation identified by\n``operationId: delete_item``.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to delete.\nresponse : fastapi.Response\n Response object used to set the HTTP status code.\n\nReturns\n-------\nNone\n No content.\n\nRaises\n------\nHTTPException\n 404 if the item does not exist."
}
}
},
"test_model_app": {
"name": "test_model_app",
"kind": "module",
"path": "openapi_first.templates.model_app.test_model_app",
"signature": null,
"docstring": "End-to-end tests for the OpenAPI-first model CRUD example app.\n\nThese tests validate that all CRUD operations behave correctly\nagainst the in-memory mock data store using Pydantic models.\n- OpenAPI specification loading\n- OperationId-driven route binding on the server\n- OperationId-driven client invocation\n- Pydantic model-based request and response handling\n\nAll CRUD operations are exercised against an in-memory mock data store\nbacked by Pydantic domain models.\n\nThe tests assume:\n- OpenAPI-first route binding\n- Pydantic model validation\n- In-memory storage (no persistence guarantees)\n- Deterministic behavior in a single process",
"members": {
"TestClient": {
"name": "TestClient",
"kind": "alias",
"path": "openapi_first.templates.model_app.test_model_app.TestClient",
"signature": "<bound method Alias.signature of Alias('TestClient', 'fastapi.testclient.TestClient')>",
"docstring": null
},
"app": {
"name": "app",
"kind": "alias",
"path": "openapi_first.templates.model_app.test_model_app.app",
"signature": "<bound method Alias.signature of Alias('app', 'main.app')>",
"docstring": null
},
"load_openapi": {
"name": "load_openapi",
"kind": "function",
"path": "openapi_first.templates.model_app.test_model_app.load_openapi",
"signature": "<bound method Alias.signature of Alias('load_openapi', 'openapi_first.loader.load_openapi')>",
"docstring": "Load and validate an OpenAPI 3.x specification from disk.\n\nThe specification is parsed based on file extension and validated\nusing a strict OpenAPI schema validator. Any error results in an\nimmediate exception, preventing application startup.\n\nParameters\n----------\npath : str or pathlib.Path\n Filesystem path to an OpenAPI specification file.\n Supported extensions:\n - `.json`\n - `.yaml`\n - `.yml`\n\nReturns\n-------\ndict\n Parsed and validated OpenAPI specification.\n\nRaises\n------\nOpenAPISpecLoadError\n If the file does not exist, cannot be parsed, or fails\n OpenAPI schema validation."
},
"OpenAPIClient": {
"name": "OpenAPIClient",
"kind": "class",
"path": "openapi_first.templates.model_app.test_model_app.OpenAPIClient",
"signature": "<bound method Alias.signature of Alias('OpenAPIClient', 'openapi_first.client.OpenAPIClient')>",
"docstring": "OpenAPI-first HTTP client (httpx-based).\n\n- One callable per operationId\n- Explicit parameters (path, query, headers, body)\n- No implicit schema inference or mutation",
"members": {
"spec": {
"name": "spec",
"kind": "attribute",
"path": "openapi_first.templates.model_app.test_model_app.OpenAPIClient.spec",
"signature": "<bound method Alias.signature of Alias('spec', 'openapi_first.client.OpenAPIClient.spec')>",
"docstring": null
},
"base_url": {
"name": "base_url",
"kind": "attribute",
"path": "openapi_first.templates.model_app.test_model_app.OpenAPIClient.base_url",
"signature": "<bound method Alias.signature of Alias('base_url', 'openapi_first.client.OpenAPIClient.base_url')>",
"docstring": null
},
"client": {
"name": "client",
"kind": "attribute",
"path": "openapi_first.templates.model_app.test_model_app.OpenAPIClient.client",
"signature": "<bound method Alias.signature of Alias('client', 'openapi_first.client.OpenAPIClient.client')>",
"docstring": null
},
"operations": {
"name": "operations",
"kind": "function",
"path": "openapi_first.templates.model_app.test_model_app.OpenAPIClient.operations",
"signature": "<bound method Alias.signature of Alias('operations', 'openapi_first.client.OpenAPIClient.operations')>",
"docstring": null
}
}
},
"client": {
"name": "client",
"kind": "attribute",
"path": "openapi_first.templates.model_app.test_model_app.client",
"signature": null,
"docstring": null
},
"spec": {
"name": "spec",
"kind": "attribute",
"path": "openapi_first.templates.model_app.test_model_app.spec",
"signature": null,
"docstring": null
},
"test_list_items_initial": {
"name": "test_list_items_initial",
"kind": "function",
"path": "openapi_first.templates.model_app.test_model_app.test_list_items_initial",
"signature": "<bound method Function.signature of Function('test_list_items_initial', 37, 48)>",
"docstring": "Initial items should be present."
},
"test_get_item": {
"name": "test_get_item",
"kind": "function",
"path": "openapi_first.templates.model_app.test_model_app.test_get_item",
"signature": "<bound method Function.signature of Function('test_get_item', 51, 61)>",
"docstring": "Existing item should be retrievable by ID."
},
"test_create_item": {
"name": "test_create_item",
"kind": "function",
"path": "openapi_first.templates.model_app.test_model_app.test_create_item",
"signature": "<bound method Function.signature of Function('test_create_item', 64, 84)>",
"docstring": "Creating a new item should return the created entity."
},
"test_update_item": {
"name": "test_update_item",
"kind": "function",
"path": "openapi_first.templates.model_app.test_model_app.test_update_item",
"signature": "<bound method Function.signature of Function('test_update_item', 87, 111)>",
"docstring": "Updating an item should replace its values."
},
"test_delete_item": {
"name": "test_delete_item",
"kind": "function",
"path": "openapi_first.templates.model_app.test_model_app.test_delete_item",
"signature": "<bound method Function.signature of Function('test_delete_item', 114, 124)>",
"docstring": "Deleting an item should remove it from the store."
}
}
}
}
}
}

View File

@@ -0,0 +1,39 @@
{
"module": "openapi_first.templates.model_app.main",
"content": {
"path": "openapi_first.templates.model_app.main",
"docstring": "Application entry point for an OpenAPI-first model-based CRUD example service.\n\nThis module constructs a FastAPI application exclusively from an\nOpenAPI specification and a handler namespace, without using\ndecorator-driven routing.\n\nAll HTTP routes, methods, request/response schemas, and operation\nbindings are defined in the OpenAPI document referenced by\n``openapi_path``. Python callables defined in the ``routes`` module are\nbound to OpenAPI operations strictly via ``operationId``.\n\nThis module contains no routing logic, persistence concerns, or\nframework configuration beyond application assembly.\n\nDesign guarantees:\n- OpenAPI is the single source of truth\n- No undocumented routes can exist\n- Every OpenAPI operationId must resolve to exactly one handler\n- All contract violations fail at application startup\n\nThis file is intended to be used as the ASGI entry point.\n\nExample:\n uvicorn main:app",
"objects": {
"OpenAPIFirstApp": {
"name": "OpenAPIFirstApp",
"kind": "class",
"path": "openapi_first.templates.model_app.main.OpenAPIFirstApp",
"signature": "<bound method Alias.signature of Alias('OpenAPIFirstApp', 'openapi_first.app.OpenAPIFirstApp')>",
"docstring": "FastAPI application enforcing OpenAPI-first design.\n\n`OpenAPIFirstApp` subclasses FastAPI and replaces manual route\nregistration with OpenAPI-driven binding. All routes are derived\nfrom the provided OpenAPI specification, and each operationId is\nmapped to a Python function in the supplied routes module.\n\nParameters\n----------\nopenapi_path : str\n Filesystem path to the OpenAPI 3.x specification file.\n This specification is treated as the authoritative API contract.\n\nroutes_module : module\n Python module containing handler functions whose names correspond\n exactly to OpenAPI operationId values.\n\n**fastapi_kwargs\n Additional keyword arguments passed directly to `fastapi.FastAPI`\n (e.g., title, version, middleware, lifespan handlers).\n\nRaises\n------\nOpenAPIFirstError\n If the OpenAPI specification is invalid, or if any declared\n operationId does not have a corresponding handler function.\n\nBehavior guarantees\n-------------------\n- No route can exist without an OpenAPI declaration.\n- No OpenAPI operation can exist without a handler.\n- Swagger UI and `/openapi.json` always reflect the provided spec.\n- Handler functions remain framework-agnostic and testable.\n\nExample\n-------\n>>> from openapi_first import OpenAPIFirstApp\n>>> import app.routes as routes\n>>>\n>>> app = OpenAPIFirstApp(\n... openapi_path=\"app/openapi.json\",\n... routes_module=routes,\n... title=\"Example Service\"\n... )",
"members": {
"openapi": {
"name": "openapi",
"kind": "attribute",
"path": "openapi_first.templates.model_app.main.OpenAPIFirstApp.openapi",
"signature": "<bound method Alias.signature of Alias('openapi', 'openapi_first.app.OpenAPIFirstApp.openapi')>",
"docstring": null
}
}
},
"routes": {
"name": "routes",
"kind": "alias",
"path": "openapi_first.templates.model_app.main.routes",
"signature": "<bound method Alias.signature of Alias('routes', 'routes')>",
"docstring": null
},
"app": {
"name": "app",
"kind": "attribute",
"path": "openapi_first.templates.model_app.main.app",
"signature": null,
"docstring": null
}
}
}
}

View File

@@ -0,0 +1,62 @@
{
"module": "openapi_first.templates.model_app.models",
"content": {
"path": "openapi_first.templates.model_app.models",
"docstring": "Pydantic domain models for the CRUD example.\n\nThis module defines Pydantic models that represent the domain entities\nused by the service. These models are referenced by the OpenAPI\nspecification for request and response schemas.\n\nThe models are declarative and framework-agnostic. They contain no\npersistence logic, validation beyond type constraints, or business\nbehavior.\n\nThis module is not part of the ``openapi_first`` library API surface.\nIt exists solely to support the example application template.",
"objects": {
"BaseModel": {
"name": "BaseModel",
"kind": "alias",
"path": "openapi_first.templates.model_app.models.BaseModel",
"signature": "<bound method Alias.signature of Alias('BaseModel', 'pydantic.BaseModel')>",
"docstring": null
},
"ItemBase": {
"name": "ItemBase",
"kind": "class",
"path": "openapi_first.templates.model_app.models.ItemBase",
"signature": "<bound method Class.signature of Class('ItemBase', 19, 27)>",
"docstring": "Base domain model for an item.\n\nDefines fields common to all item representations.",
"members": {
"name": {
"name": "name",
"kind": "attribute",
"path": "openapi_first.templates.model_app.models.ItemBase.name",
"signature": null,
"docstring": null
},
"price": {
"name": "price",
"kind": "attribute",
"path": "openapi_first.templates.model_app.models.ItemBase.price",
"signature": null,
"docstring": null
}
}
},
"ItemCreate": {
"name": "ItemCreate",
"kind": "class",
"path": "openapi_first.templates.model_app.models.ItemCreate",
"signature": "<bound method Class.signature of Class('ItemCreate', 30, 39)>",
"docstring": "Domain model for item creation requests.\n\nThis model is used for request bodies when creating new items.\nIt intentionally excludes the ``id`` field, which is assigned\nby the service."
},
"Item": {
"name": "Item",
"kind": "class",
"path": "openapi_first.templates.model_app.models.Item",
"signature": "<bound method Class.signature of Class('Item', 42, 50)>",
"docstring": "Domain model for a persisted item.\n\nThis model represents the full item state returned in responses,\nincluding the server-assigned identifier.",
"members": {
"id": {
"name": "id",
"kind": "attribute",
"path": "openapi_first.templates.model_app.models.Item.id",
"signature": null,
"docstring": null
}
}
}
}
}
}

View File

@@ -0,0 +1,65 @@
{
"module": "openapi_first.templates.model_app.routes",
"content": {
"path": "openapi_first.templates.model_app.routes",
"docstring": "CRUD route handlers bound via OpenAPI operationId.\n\nThis module defines OpenAPI-bound operation handlers for a model-based\nCRUD service. Functions in this module are bound to HTTP routes\nexclusively via OpenAPI ``operationId`` values.\n\nHandlers explicitly control HTTP response status codes to ensure runtime\nbehavior matches the OpenAPI contract. Domain models defined using\nPydantic are used for request and response payloads.\n\nNo routing decorators, path definitions, or implicit framework behavior\nappear in this module. All routing, HTTP methods, and schemas are defined\nin the OpenAPI specification.",
"objects": {
"Response": {
"name": "Response",
"kind": "alias",
"path": "openapi_first.templates.model_app.routes.Response",
"signature": "<bound method Alias.signature of Alias('Response', 'fastapi.Response')>",
"docstring": null
},
"HTTPException": {
"name": "HTTPException",
"kind": "alias",
"path": "openapi_first.templates.model_app.routes.HTTPException",
"signature": "<bound method Alias.signature of Alias('HTTPException', 'fastapi.HTTPException')>",
"docstring": null
},
"ItemCreate": {
"name": "ItemCreate",
"kind": "alias",
"path": "openapi_first.templates.model_app.routes.ItemCreate",
"signature": "<bound method Alias.signature of Alias('ItemCreate', 'models.ItemCreate')>",
"docstring": null
},
"list_items": {
"name": "list_items",
"kind": "function",
"path": "openapi_first.templates.model_app.routes.list_items",
"signature": "<bound method Function.signature of Function('list_items', 29, 41)>",
"docstring": "List all items.\n\nImplements the OpenAPI operation identified by\n``operationId: list_items``.\n\nReturns\n-------\nlist[Item]\n A list of item domain objects."
},
"get_item": {
"name": "get_item",
"kind": "function",
"path": "openapi_first.templates.model_app.routes.get_item",
"signature": "<bound method Function.signature of Function('get_item', 44, 69)>",
"docstring": "Retrieve a single item by ID.\n\nImplements the OpenAPI operation identified by\n``operationId: get_item``.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to retrieve.\n\nReturns\n-------\nItem\n The requested item.\n\nRaises\n------\nHTTPException\n 404 if the item does not exist."
},
"create_item": {
"name": "create_item",
"kind": "function",
"path": "openapi_first.templates.model_app.routes.create_item",
"signature": "<bound method Function.signature of Function('create_item', 72, 93)>",
"docstring": "Create a new item.\n\nImplements the OpenAPI operation identified by\n``operationId: create_item``.\n\nParameters\n----------\npayload : ItemCreate\n Request body describing the item to create.\nresponse : fastapi.Response\n Response object used to set the HTTP status code.\n\nReturns\n-------\nItem\n The newly created item."
},
"update_item": {
"name": "update_item",
"kind": "function",
"path": "openapi_first.templates.model_app.routes.update_item",
"signature": "<bound method Function.signature of Function('update_item', 96, 123)>",
"docstring": "Update an existing item.\n\nImplements the OpenAPI operation identified by\n``operationId: update_item``.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to update.\npayload : ItemCreate\n New item data.\n\nReturns\n-------\nItem\n The updated item.\n\nRaises\n------\nHTTPException\n 404 if the item does not exist."
},
"delete_item": {
"name": "delete_item",
"kind": "function",
"path": "openapi_first.templates.model_app.routes.delete_item",
"signature": "<bound method Function.signature of Function('delete_item', 126, 156)>",
"docstring": "Delete an existing item.\n\nImplements the OpenAPI operation identified by\n``operationId: delete_item``.\n\nParameters\n----------\nitem_id : int\n Identifier of the item to delete.\nresponse : fastapi.Response\n Response object used to set the HTTP status code.\n\nReturns\n-------\nNone\n No content.\n\nRaises\n------\nHTTPException\n 404 if the item does not exist."
}
}
}
}

View File

@@ -0,0 +1,116 @@
{
"module": "openapi_first.templates.model_app.test_model_app",
"content": {
"path": "openapi_first.templates.model_app.test_model_app",
"docstring": "End-to-end tests for the OpenAPI-first model CRUD example app.\n\nThese tests validate that all CRUD operations behave correctly\nagainst the in-memory mock data store using Pydantic models.\n- OpenAPI specification loading\n- OperationId-driven route binding on the server\n- OperationId-driven client invocation\n- Pydantic model-based request and response handling\n\nAll CRUD operations are exercised against an in-memory mock data store\nbacked by Pydantic domain models.\n\nThe tests assume:\n- OpenAPI-first route binding\n- Pydantic model validation\n- In-memory storage (no persistence guarantees)\n- Deterministic behavior in a single process",
"objects": {
"TestClient": {
"name": "TestClient",
"kind": "alias",
"path": "openapi_first.templates.model_app.test_model_app.TestClient",
"signature": "<bound method Alias.signature of Alias('TestClient', 'fastapi.testclient.TestClient')>",
"docstring": null
},
"app": {
"name": "app",
"kind": "alias",
"path": "openapi_first.templates.model_app.test_model_app.app",
"signature": "<bound method Alias.signature of Alias('app', 'main.app')>",
"docstring": null
},
"load_openapi": {
"name": "load_openapi",
"kind": "function",
"path": "openapi_first.templates.model_app.test_model_app.load_openapi",
"signature": "<bound method Alias.signature of Alias('load_openapi', 'openapi_first.loader.load_openapi')>",
"docstring": "Load and validate an OpenAPI 3.x specification from disk.\n\nThe specification is parsed based on file extension and validated\nusing a strict OpenAPI schema validator. Any error results in an\nimmediate exception, preventing application startup.\n\nParameters\n----------\npath : str or pathlib.Path\n Filesystem path to an OpenAPI specification file.\n Supported extensions:\n - `.json`\n - `.yaml`\n - `.yml`\n\nReturns\n-------\ndict\n Parsed and validated OpenAPI specification.\n\nRaises\n------\nOpenAPISpecLoadError\n If the file does not exist, cannot be parsed, or fails\n OpenAPI schema validation."
},
"OpenAPIClient": {
"name": "OpenAPIClient",
"kind": "class",
"path": "openapi_first.templates.model_app.test_model_app.OpenAPIClient",
"signature": "<bound method Alias.signature of Alias('OpenAPIClient', 'openapi_first.client.OpenAPIClient')>",
"docstring": "OpenAPI-first HTTP client (httpx-based).\n\n- One callable per operationId\n- Explicit parameters (path, query, headers, body)\n- No implicit schema inference or mutation",
"members": {
"spec": {
"name": "spec",
"kind": "attribute",
"path": "openapi_first.templates.model_app.test_model_app.OpenAPIClient.spec",
"signature": "<bound method Alias.signature of Alias('spec', 'openapi_first.client.OpenAPIClient.spec')>",
"docstring": null
},
"base_url": {
"name": "base_url",
"kind": "attribute",
"path": "openapi_first.templates.model_app.test_model_app.OpenAPIClient.base_url",
"signature": "<bound method Alias.signature of Alias('base_url', 'openapi_first.client.OpenAPIClient.base_url')>",
"docstring": null
},
"client": {
"name": "client",
"kind": "attribute",
"path": "openapi_first.templates.model_app.test_model_app.OpenAPIClient.client",
"signature": "<bound method Alias.signature of Alias('client', 'openapi_first.client.OpenAPIClient.client')>",
"docstring": null
},
"operations": {
"name": "operations",
"kind": "function",
"path": "openapi_first.templates.model_app.test_model_app.OpenAPIClient.operations",
"signature": "<bound method Alias.signature of Alias('operations', 'openapi_first.client.OpenAPIClient.operations')>",
"docstring": null
}
}
},
"client": {
"name": "client",
"kind": "attribute",
"path": "openapi_first.templates.model_app.test_model_app.client",
"signature": null,
"docstring": null
},
"spec": {
"name": "spec",
"kind": "attribute",
"path": "openapi_first.templates.model_app.test_model_app.spec",
"signature": null,
"docstring": null
},
"test_list_items_initial": {
"name": "test_list_items_initial",
"kind": "function",
"path": "openapi_first.templates.model_app.test_model_app.test_list_items_initial",
"signature": "<bound method Function.signature of Function('test_list_items_initial', 37, 48)>",
"docstring": "Initial items should be present."
},
"test_get_item": {
"name": "test_get_item",
"kind": "function",
"path": "openapi_first.templates.model_app.test_model_app.test_get_item",
"signature": "<bound method Function.signature of Function('test_get_item', 51, 61)>",
"docstring": "Existing item should be retrievable by ID."
},
"test_create_item": {
"name": "test_create_item",
"kind": "function",
"path": "openapi_first.templates.model_app.test_model_app.test_create_item",
"signature": "<bound method Function.signature of Function('test_create_item', 64, 84)>",
"docstring": "Creating a new item should return the created entity."
},
"test_update_item": {
"name": "test_update_item",
"kind": "function",
"path": "openapi_first.templates.model_app.test_model_app.test_update_item",
"signature": "<bound method Function.signature of Function('test_update_item', 87, 111)>",
"docstring": "Updating an item should replace its values."
},
"test_delete_item": {
"name": "test_delete_item",
"kind": "function",
"path": "openapi_first.templates.model_app.test_model_app.test_delete_item",
"signature": "<bound method Function.signature of Function('test_delete_item', 114, 124)>",
"docstring": "Deleting an item should remove it from the store."
}
}
}
}

90
mcp_docs/nav.json Normal file
View File

@@ -0,0 +1,90 @@
[
{
"module": "openapi_first",
"resource": "doc://modules/openapi_first"
},
{
"module": "openapi_first.app",
"resource": "doc://modules/openapi_first.app"
},
{
"module": "openapi_first.binder",
"resource": "doc://modules/openapi_first.binder"
},
{
"module": "openapi_first.cli",
"resource": "doc://modules/openapi_first.cli"
},
{
"module": "openapi_first.client",
"resource": "doc://modules/openapi_first.client"
},
{
"module": "openapi_first.errors",
"resource": "doc://modules/openapi_first.errors"
},
{
"module": "openapi_first.loader",
"resource": "doc://modules/openapi_first.loader"
},
{
"module": "openapi_first.templates",
"resource": "doc://modules/openapi_first.templates"
},
{
"module": "openapi_first.templates.crud_app",
"resource": "doc://modules/openapi_first.templates.crud_app"
},
{
"module": "openapi_first.templates.crud_app.data",
"resource": "doc://modules/openapi_first.templates.crud_app.data"
},
{
"module": "openapi_first.templates.crud_app.main",
"resource": "doc://modules/openapi_first.templates.crud_app.main"
},
{
"module": "openapi_first.templates.crud_app.routes",
"resource": "doc://modules/openapi_first.templates.crud_app.routes"
},
{
"module": "openapi_first.templates.crud_app.test_crud_app",
"resource": "doc://modules/openapi_first.templates.crud_app.test_crud_app"
},
{
"module": "openapi_first.templates.health_app",
"resource": "doc://modules/openapi_first.templates.health_app"
},
{
"module": "openapi_first.templates.health_app.main",
"resource": "doc://modules/openapi_first.templates.health_app.main"
},
{
"module": "openapi_first.templates.health_app.routes",
"resource": "doc://modules/openapi_first.templates.health_app.routes"
},
{
"module": "openapi_first.templates.model_app",
"resource": "doc://modules/openapi_first.templates.model_app"
},
{
"module": "openapi_first.templates.model_app.data",
"resource": "doc://modules/openapi_first.templates.model_app.data"
},
{
"module": "openapi_first.templates.model_app.main",
"resource": "doc://modules/openapi_first.templates.model_app.main"
},
{
"module": "openapi_first.templates.model_app.models",
"resource": "doc://modules/openapi_first.templates.model_app.models"
},
{
"module": "openapi_first.templates.model_app.routes",
"resource": "doc://modules/openapi_first.templates.model_app.routes"
},
{
"module": "openapi_first.templates.model_app.test_model_app",
"resource": "doc://modules/openapi_first.templates.model_app.test_model_app"
}
]

View File

@@ -1,5 +1,5 @@
site_name: Aetoskia Mail Intake
site_description: Format-agnostic document reading, parsing, and scraping framework
site_name: Aetoskia OpenAPI First
site_description: Contract-first FastAPI application bootstrap and specification-driven HTTP client.
theme:
name: material
@@ -17,13 +17,13 @@ theme:
- navigation.instant
- content.code.copy
- content.code.annotate
plugins:
- search
- mkdocstrings:
- search
- mkdocstrings:
handlers:
python:
paths: ["."]
paths:
- .
options:
docstring_style: google
show_source: false
@@ -36,16 +36,12 @@ plugins:
group_by_category: true
nav:
- Home: openapi_first/index.md
- Core:
- OpenAPI-First App: openapi_first/app.md
- Route Binder: openapi_first/binder.md
- Spec Loaders: openapi_first/loader.md
- Client: openapi_first/client.md
- CLI:
- Home: openapi_first/cli.md
- Errors:
- Error Hierarchy: openapi_first/errors.md
- Home: openapi_first/index.md
- Application Bootstrap:
- openapi_first/app.md
- openapi_first/binder.md
- Core Utilities:
- openapi_first/loader.md
- openapi_first/errors.md
- OpenAPI Client:
- openapi_first/client.md

View File

@@ -49,6 +49,32 @@ Runtime dependencies are intentionally minimal:
The ASGI server (e.g., uvicorn) is an application-level dependency and is
not bundled with this library.
----------------------------------------------------------------------
Command-Line Interface (Scaffolding, Templates)
----------------------------------------------------------------------
FastAPI OpenAPI First ships with a small CLI for bootstrapping
OpenAPI-first FastAPI applications from bundled templates.
List available application templates:
openapi-first --list
Create a new application using the default template:
openapi-first
Create a new application using a specific template:
openapi-first health_app
Create a new application in a custom directory:
openapi-first health_app my-service
The CLI copies template files verbatim into the target directory.
No code is generated or modified beyond the copied scaffold.
----------------------------------------------------------------------
Server-Side Usage (OpenAPI → FastAPI)
----------------------------------------------------------------------
@@ -179,6 +205,27 @@ Design Guarantees
FastAPI OpenAPI First favors correctness, explicitness, and contract
enforcement over convenience shortcuts.
## Core Philosophy
`FastAPI OpenAPI First` operates on the **Contract-as-Code** principle:
1. **Spec-Driven Routing**: The OpenAPI document *is* the router. Code only exists to fulfill established contracts.
2. **Startup Fail-Fast**: Binding mismatches (missing handlers or extra operations) are detected during app initialization, not at runtime.
3. **Decoupled Symmetry**: The same specification drives both the FastAPI server and the `httpx`-based client, ensuring type-safe communication.
## Documentation Design
Follow these "AI-Native" docstring principles to maximize developer and agent productivity:
### For Humans
- **Logical Grouping**: Document the Loader, Binder, and Client as distinct infrastructure layers.
- **Spec Snippets**: Always include the corresponding OpenAPI YAML/JSON snippet alongside Python examples.
### For LLMs
- **Full Path Linking**: Refer to cross-module dependencies using their full dotted paths (e.g., `openapi_first.loader.load_openapi`).
- **Complete Stubs**: Maintain high-fidelity `.pyi` stubs for all public interfaces to provide an optimized machine-context.
- **Traceable Errors**: Use specific `: description` pairs in `Raises` blocks to allow agents to accurately map errors to spec violations.
"""
from . import app

View File

@@ -0,0 +1,7 @@
from . import app as app
from . import binder as binder
from . import loader as loader
from . import client as client
from . import errors as errors
__all__ = ["app", "binder", "loader", "client", "errors"]

5
openapi_first/app.pyi Normal file
View File

@@ -0,0 +1,5 @@
from fastapi import FastAPI
from typing import Any
class OpenAPIFirstApp(FastAPI):
def __init__(self, *, openapi_path: str, routes_module: Any, **fastapi_kwargs: Any) -> None: ...

4
openapi_first/binder.pyi Normal file
View File

@@ -0,0 +1,4 @@
from typing import Any, Dict
from fastapi import FastAPI
def bind_routes(app: FastAPI, spec: Dict[str, Any], routes_module: Any) -> None: ...

View File

@@ -4,16 +4,8 @@ openapi_first.cli
Command-line interface for FastAPI OpenAPI-first scaffolding utilities.
This module provides a small, focused CLI intended to help developers
quickly bootstrap OpenAPI-first FastAPI services using bundled project
templates.
Currently supported scaffolds:
- Health check service (minimal OpenAPI-first application)
The CLI copies versioned templates packaged with the library into a
user-specified directory, allowing rapid local development without
manual setup.
This CLI bootstraps OpenAPI-first FastAPI applications from versioned,
bundled templates packaged with the library.
"""
import argparse
@@ -22,68 +14,75 @@ from pathlib import Path
from importlib import resources
def copy_health_app_template(target_dir: Path) -> None:
DEFAULT_TEMPLATE = "health_app"
def available_templates() -> list[str]:
"""
Copy the bundled OpenAPI-first health app template into a directory.
Return a list of available application templates.
"""
root = resources.files("openapi_first.templates")
return sorted(
item.name
for item in root.iterdir()
if item.is_dir() and not item.name.startswith("_")
)
This function copies a fully working, minimal OpenAPI-first FastAPI
health check application from the package's embedded templates into
the specified target directory.
The target directory will be created if it does not already exist.
Existing files may be overwritten.
Parameters
----------
target_dir : pathlib.Path
Destination directory into which the health app template
should be copied.
Raises
------
FileNotFoundError
If the bundled health app template cannot be located.
def copy_template(template: str, target_dir: Path) -> None:
"""
Copy a bundled OpenAPI-first application template into a directory.
"""
target_dir = target_dir.resolve()
target_dir.mkdir(parents=True, exist_ok=True)
with resources.files("openapi_first.templates").joinpath(
"health_app"
) as src:
shutil.copytree(src, target_dir, dirs_exist_ok=True)
root = resources.files("openapi_first.templates")
src = root / template
if not src.exists():
raise FileNotFoundError(
f"Template '{template}' not found. "
f"Available templates: {', '.join(available_templates())}"
)
with resources.as_file(src) as path:
shutil.copytree(path, target_dir, dirs_exist_ok=True)
def main() -> None:
"""
Entry point for the FastAPI OpenAPI-first CLI.
Parses command-line arguments and initializes a new OpenAPI-first
health check application by copying the bundled template into the
specified directory.
If no target path is provided, the scaffold is created in a directory
named ``health-app`` in the current working directory.
Example
-------
Create a health app in the default directory::
openapi-first
Create a health app in a custom directory::
openapi-first my-service
"""
parser = argparse.ArgumentParser(
description="FastAPI OpenAPI-first scaffolding tools"
)
parser.add_argument(
"template",
nargs="?",
default=DEFAULT_TEMPLATE,
help=f"Template name (default: {DEFAULT_TEMPLATE})",
)
parser.add_argument(
"path",
nargs="?",
default="health-app",
help="Target directory for the health app",
default=None,
help="Target directory (defaults to template name)",
)
parser.add_argument(
"--list",
action="store_true",
help="List available templates and exit",
)
args = parser.parse_args()
copy_health_app_template(Path(args.path))
print(f"Health app created at {args.path}")
if args.list:
for name in available_templates():
print(name)
return
target = Path(args.path or args.template.replace("_", "-"))
try:
copy_template(args.template, target)
except Exception as exc:
raise SystemExit(str(exc)) from exc
print(f"Template '{args.template}' created at {target}")

13
openapi_first/client.pyi Normal file
View File

@@ -0,0 +1,13 @@
from typing import Any, Callable, Dict, Optional
import httpx
from .errors import OpenAPIFirstError
class OpenAPIClientError(OpenAPIFirstError): ...
class OpenAPIClient:
spec: Dict[str, Any]
base_url: str
client: httpx.Client
def __init__(self, spec: Dict[str, Any], base_url: Optional[str] = ..., client: Optional[httpx.Client] = ...) -> None: ...
def __getattr__(self, name: str) -> Callable[..., httpx.Response]: ...
def operations(self) -> Dict[str, Callable[..., httpx.Response]]: ...

6
openapi_first/errors.pyi Normal file
View File

@@ -0,0 +1,6 @@
from typing import Optional
class OpenAPIFirstError(Exception): ...
class MissingOperationHandler(OpenAPIFirstError):
def __init__(self, *, path: str, method: str, operation_id: Optional[str] = ...) -> None: ...

8
openapi_first/loader.pyi Normal file
View File

@@ -0,0 +1,8 @@
from pathlib import Path
from typing import Any, Dict, Union
from .errors import OpenAPIFirstError
class OpenAPISpecLoadError(OpenAPIFirstError): ...
def load_openapi(path: Union[str, Path]) -> Dict[str, Any]: ...

View File

@@ -0,0 +1,18 @@
"""
Application templates for FastAPI OpenAPI First.
This package contains example and scaffolding templates intended to be
copied into user projects via the ``openapi-first`` CLI.
Templates in this package are:
- Reference implementations of OpenAPI-first services
- Not part of the ``openapi_first`` public or internal API
- Not intended to be imported as runtime dependencies
The presence of this file exists solely to:
- Mark the directory as an explicit Python package
- Enable deterministic tooling behavior (documentation, packaging)
- Avoid accidental traversal of non-package directories
No code in this package should be imported by library consumers.
"""

View File

@@ -0,0 +1,99 @@
"""
OpenAPI-first CRUD application template.
This package contains a complete, minimal example of an OpenAPI-first
CRUD service built using the ``openapi_first`` library.
The application is assembled exclusively from:
- an OpenAPI specification (``openapi.yaml``)
- a handler namespace implementing CRUD operations (``routes``)
- an in-memory mock data store (``data``)
All HTTP routes, methods, schemas, and operation bindings are defined
in the OpenAPI specification and enforced at application startup.
No decorator-driven routing or implicit framework behavior is used.
This template demonstrates:
- operationId-driven server-side route binding
- explicit HTTP status code control in handlers
- operationId-driven client usage against the same OpenAPI contract
- end-to-end validation using in-memory data and tests
----------------------------------------------------------------------
Scaffolding via CLI
----------------------------------------------------------------------
Create a new CRUD example service using the bundled template:
openapi-first crud_app
Create the service in a custom directory:
openapi-first crud_app my-crud-service
List all available application templates:
openapi-first --list
The CLI copies template files verbatim into the target directory.
No code is generated or modified beyond the copied scaffold.
----------------------------------------------------------------------
Client Usage Example
----------------------------------------------------------------------
The same OpenAPI specification used by the server can be used to
construct a strict, operationId-driven HTTP client.
Example client calls for CRUD operations:
from openapi_first.loader import load_openapi
from openapi_first.client import OpenAPIClient
spec = load_openapi("openapi.yaml")
client = OpenAPIClient(spec)
# List items
response = client.list_items()
# Get item by ID
response = client.get_item(
path_params={"item_id": 1}
)
# Create item
response = client.create_item(
body={"name": "Orange", "price": 0.8}
)
# Update item
response = client.update_item(
path_params={"item_id": 1},
body={"name": "Green Apple", "price": 0.6},
)
# Delete item
response = client.delete_item(
path_params={"item_id": 1}
)
Client guarantees:
- One callable per OpenAPI ``operationId``
- No hardcoded URLs or HTTP methods in user code
- Path and request parameters must match the OpenAPI specification
- Invalid or incomplete OpenAPI specs fail at client construction time
----------------------------------------------------------------------
Non-Goals
----------------------------------------------------------------------
This template is intentionally minimal and is NOT:
- production-ready
- persistent or concurrency-safe
- a reference architecture for data storage
It exists solely as a copyable example for learning, testing, and
bootstrapping OpenAPI-first services.
This package is not part of the ``openapi_first`` library API surface.
"""

View File

@@ -3,27 +3,88 @@ In-memory mock data store for CRUD example.
This module intentionally avoids persistence and concurrency guarantees.
It is suitable for demos, tests, and scaffolding only.
It intentionally avoids
- persistence
- concurrency guarantees
- validation
- error handling
The implementation is suitable for:
- demonstrations
- tests
- scaffolding and example services
It is explicitly NOT suitable for production use.
This module is not part of the ``openapi_first`` library API surface.
"""
from typing import Dict
# In-memory storage keyed by item ID.
_items: Dict[int, dict] = {
1: {"id": 1, "name": "Apple", "price": 0.5},
2: {"id": 2, "name": "Banana", "price": 0.3},
}
# Auto-incrementing ID counter.
_next_id = 3
def list_items():
"""
Return all items in the data store.
This function performs no filtering, pagination, or sorting.
The returned collection reflects the current in-memory state.
Returns
-------
list[dict]
A list of item representations.
"""
return list(_items.values())
def get_item(item_id: int):
"""
Retrieve a single item by ID.
This function assumes the item exists and will raise ``KeyError``
if the ID is not present in the store.
Parameters
----------
item_id : int
Identifier of the item to retrieve.
Returns
-------
dict
The stored item representation.
"""
return _items[item_id]
def create_item(payload: dict):
"""
Create a new item in the data store.
A new integer ID is assigned automatically. No validation is
performed on the provided payload.
Parameters
----------
payload : dict
Item attributes excluding the ``id`` field.
Returns
-------
dict
The newly created item, including its assigned ID.
"""
global _next_id
item = {"id": _next_id, **payload}
_items[_next_id] = item
@@ -32,10 +93,40 @@ def create_item(payload: dict):
def update_item(item_id: int, payload: dict):
"""
Replace an existing item in the data store.
This function overwrites the existing item entirely and does not
perform partial updates or validation. If the item does not exist,
it will be created implicitly.
Parameters
----------
item_id : int
Identifier of the item to update.
payload : dict
Item attributes excluding the ``id`` field.
Returns
-------
dict
The updated item representation.
"""
item = {"id": item_id, **payload}
_items[item_id] = item
return item
def delete_item(item_id: int):
"""
Remove an item from the data store.
This function assumes the item exists and will raise ``KeyError``
if the ID is not present.
Parameters
----------
item_id : int
Identifier of the item to delete.
"""
del _items[item_id]

View File

@@ -1,3 +1,30 @@
"""
Application entry point for an OpenAPI-first CRUD example service.
This module constructs a FastAPI application exclusively from an
OpenAPI specification and a handler namespace, without using
decorator-driven routing.
All HTTP routes, methods, request/response schemas, and operation
bindings are defined in the OpenAPI document referenced by
``openapi_path``. Python callables defined in the ``routes`` module are
bound to OpenAPI operations strictly via ``operationId``.
This module contains no routing logic, persistence concerns, or
framework configuration beyond application assembly.
Design guarantees:
- OpenAPI is the single source of truth
- No undocumented routes can exist
- Every OpenAPI operationId must resolve to exactly one handler
- All contract violations fail at application startup
This file is intended to be used as the ASGI entry point.
Example:
uvicorn main:app
"""
from openapi_first.app import OpenAPIFirstApp
import routes

View File

@@ -3,6 +3,19 @@ CRUD route handlers bound via OpenAPI operationId.
These handlers explicitly control HTTP status codes to ensure
runtime behavior matches the OpenAPI contract.
This module defines OpenAPI-bound operation handlers for a simple CRUD
service. Functions in this module are bound to HTTP routes exclusively
via OpenAPI ``operationId`` values.
Handlers explicitly control HTTP response status codes to ensure runtime
behavior matches the OpenAPI contract. Error conditions are translated
into explicit HTTP responses rather than relying on implicit framework
behavior.
No routing decorators or path definitions appear in this module. All
routing, HTTP methods, and schemas are defined in the OpenAPI
specification.
"""
from fastapi import Response, HTTPException
@@ -17,10 +30,42 @@ from data import (
def list_items():
"""
List all items.
Implements the OpenAPI operation identified by
``operationId: list_items``.
Returns
-------
list[dict]
A list of item representations.
"""
return _list_items()
def get_item(item_id: int):
"""
Retrieve a single item by ID.
Implements the OpenAPI operation identified by
``operationId: get_item``.
Parameters
----------
item_id : int
Identifier of the item to retrieve.
Returns
-------
dict
The requested item.
Raises
------
HTTPException
404 if the item does not exist.
"""
try:
return _get_item(item_id)
except KeyError:
@@ -28,12 +73,53 @@ def get_item(item_id: int):
def create_item(payload: dict, response: Response):
"""
Create a new item.
Implements the OpenAPI operation identified by
``operationId: create_item``.
Parameters
----------
payload : dict
Item attributes excluding the ``id`` field.
response : fastapi.Response
Response object used to set the HTTP status code.
Returns
-------
dict
The newly created item.
"""
item = _create_item(payload)
response.status_code = 201
return item
def update_item(item_id: int, payload: dict):
"""
Update an existing item.
Implements the OpenAPI operation identified by
``operationId: update_item``.
Parameters
----------
item_id : int
Identifier of the item to update.
payload : dict
Item attributes excluding the ``id`` field.
Returns
-------
dict
The updated item.
Raises
------
HTTPException
404 if the item does not exist.
"""
try:
return _update_item(item_id, payload)
except KeyError:
@@ -41,10 +127,32 @@ def update_item(item_id: int, payload: dict):
def delete_item(item_id: int, response: Response):
"""
Delete an existing item.
Implements the OpenAPI operation identified by
``operationId: delete_item``.
Parameters
----------
item_id : int
Identifier of the item to delete.
response : fastapi.Response
Response object used to set the HTTP status code.
Returns
-------
None
No content.
Raises
------
HTTPException
404 if the item does not exist.
"""
try:
_delete_item(item_id)
except KeyError:
raise HTTPException(status_code=404, detail="Item not found")
response.status_code = 204
return None

View File

@@ -3,11 +3,20 @@ End-to-end tests for the OpenAPI-first CRUD example app.
These tests validate that all CRUD operations behave correctly
against the in-memory mock data store.
- OpenAPI specification loading
- OperationId-driven route binding on the server
- OperationId-driven client invocation
- Correct HTTP status codes and response payloads
The tests exercise all CRUD operations against an in-memory mock data
store and assume deterministic behavior within a single process.
The tests assume:
- OpenAPI-first route binding
- In-memory storage (no persistence guarantees)
- Deterministic behavior in a single process
- One-to-one correspondence between OpenAPI operationId values and
server/client callables
"""
from fastapi.testclient import TestClient

View File

@@ -0,0 +1,65 @@
"""
OpenAPI-first FastAPI application template.
This package contains a minimal, fully working example of an
OpenAPI-first FastAPI service built using the ``openapi_first`` library.
The application is assembled exclusively from:
- an OpenAPI specification (``openapi.yaml``)
- a handler namespace (``routes``)
No routing decorators, implicit behavior, or framework-specific
convenience abstractions are used. All HTTP routes, methods, and
operation bindings are defined in OpenAPI and enforced at application
startup.
This package is intended to be copied as a starting point for new
services via the ``openapi-first`` CLI. It is not part of the
``openapi_first`` library API surface.
----------------------------------------------------------------------
Scaffolding via CLI
----------------------------------------------------------------------
Create a new OpenAPI-first health check service using the bundled
template:
openapi-first health_app
Create the service in a custom directory:
openapi-first health_app my-health-service
List all available application templates:
openapi-first --list
The CLI copies template files verbatim into the target directory.
No code is generated or modified beyond the copied scaffold.
----------------------------------------------------------------------
Client Usage Example
----------------------------------------------------------------------
The same OpenAPI specification used by the server can be used to
construct a strict, operationId-driven HTTP client.
Example client call for the ``get_health`` operation:
from openapi_first.loader import load_openapi
from openapi_first.client import OpenAPIClient
spec = load_openapi("openapi.yaml")
client = OpenAPIClient(spec)
response = client.get_health()
assert response.status_code == 200
assert response.json() == {"status": "ok"}
Client guarantees:
- One callable per OpenAPI ``operationId``
- No hardcoded URLs or HTTP methods in user code
- Path and request parameters must match the OpenAPI specification
- Invalid or incomplete OpenAPI specs fail at client construction time
"""

View File

@@ -1,3 +1,31 @@
"""
Application entry point for an OpenAPI-first FastAPI service.
This module constructs a FastAPI application exclusively from an
OpenAPI specification and a handler namespace, without using
decorator-driven routing.
All HTTP routes, methods, and operation bindings are defined in the
OpenAPI document referenced by ``openapi_path``. Python callables
defined in the ``routes`` module are bound to OpenAPI operations
strictly via ``operationId``.
This module contains no routing logic, request handling, or framework
configuration beyond application assembly.
Design guarantees:
- OpenAPI is the single source of truth
- No undocumented routes can exist
- Every OpenAPI operationId must resolve to exactly one handler
- All contract violations fail at application startup
This file is intended to be used as the ASGI entry point.
Example:
uvicorn main:app
"""
from openapi_first.app import OpenAPIFirstApp
import routes

View File

@@ -1,2 +1,32 @@
"""
OpenAPI operation handlers.
This module defines pure Python callables that implement OpenAPI
operations for this service. Functions in this module are bound to HTTP
routes exclusively via OpenAPI ``operationId`` values.
No routing decorators, HTTP metadata, or framework-specific logic
should appear here. All request/response semantics are defined in the
OpenAPI specification.
This module serves solely as an operationId namespace.
"""
def get_health():
"""
Health check operation handler.
This function implements the OpenAPI operation identified by
``operationId: get_health``.
It contains no routing metadata or framework-specific logic.
Request binding, HTTP method, and response semantics are defined
exclusively by the OpenAPI specification.
Returns
-------
dict
A minimal liveness payload indicating service health.
"""
return {"status": "ok"}

View File

@@ -0,0 +1,102 @@
"""
OpenAPI-first model-based CRUD application template.
This package contains a complete, minimal example of an OpenAPI-first
CRUD service that uses explicit Pydantic domain models for request and
response schemas.
The application is assembled exclusively from:
- an OpenAPI specification (``openapi.yaml``)
- a handler namespace implementing CRUD operations (``routes``)
- Pydantic domain models (``models``)
- an in-memory mock data store (``data``)
All HTTP routes, methods, schemas, and operation bindings are defined
in the OpenAPI specification and enforced at application startup.
No decorator-driven routing or implicit framework behavior is used.
This template demonstrates:
- operationId-driven server-side route binding
- explicit request and response modeling with Pydantic
- explicit HTTP status code control in handlers
- operationId-driven client usage against the same OpenAPI contract
- end-to-end validation using in-memory data and tests
----------------------------------------------------------------------
Scaffolding via CLI
----------------------------------------------------------------------
Create a new model-based CRUD example service using the bundled template:
openapi-first model_app
Create the service in a custom directory:
openapi-first model_app my-model-service
List all available application templates:
openapi-first --list
The CLI copies template files verbatim into the target directory.
No code is generated or modified beyond the copied scaffold.
----------------------------------------------------------------------
Client Usage Example
----------------------------------------------------------------------
The same OpenAPI specification used by the server can be used to
construct a strict, operationId-driven HTTP client.
Example client calls for model-based CRUD operations:
from openapi_first.loader import load_openapi
from openapi_first.client import OpenAPIClient
spec = load_openapi("openapi.yaml")
client = OpenAPIClient(spec)
# List items
response = client.list_items()
# Get item by ID
response = client.get_item(
path_params={"item_id": 1}
)
# Create item
response = client.create_item(
body={"name": "Orange", "price": 0.8}
)
# Update item
response = client.update_item(
path_params={"item_id": 1},
body={"name": "Green Apple", "price": 0.6},
)
# Delete item
response = client.delete_item(
path_params={"item_id": 1}
)
Client guarantees:
- One callable per OpenAPI ``operationId``
- No hardcoded URLs or HTTP methods in user code
- Request and response payloads conform to Pydantic models
- Invalid or incomplete OpenAPI specs fail at client construction time
----------------------------------------------------------------------
Non-Goals
----------------------------------------------------------------------
This template is intentionally minimal and is NOT:
- production-ready
- persistent or concurrency-safe
- a reference architecture for data storage
It exists solely as a copyable example for learning, testing, and
bootstrapping OpenAPI-first services.
This package is not part of the ``openapi_first`` library API surface.
"""

View File

@@ -2,29 +2,86 @@
In-memory data store using Pydantic models.
This module is NOT thread-safe and is intended for demos and scaffolds only.
This module provides a minimal, process-local data store for the
model-based CRUD example application. It stores and returns domain
objects defined using Pydantic models and is intended solely for
demonstration and scaffolding purposes.
The implementation intentionally avoids:
- persistence
- concurrency guarantees
- transactional semantics
- validation beyond what Pydantic provides
It is not part of the ``openapi_first`` library API surface.
"""
from typing import Dict
from models import Item, ItemCreate
# In-memory storage keyed by item ID.
_items: Dict[int, Item] = {
1: Item(id=1, name="Apple", price=0.5),
2: Item(id=2, name="Banana", price=0.3),
}
# Auto-incrementing identifier.
_next_id = 3
def list_items() -> list[Item]:
"""
Return all items in the data store.
Returns
-------
list[Item]
A list of item domain objects.
"""
return list(_items.values())
def get_item(item_id: int) -> Item:
"""
Retrieve a single item by ID.
Parameters
----------
item_id : int
Identifier of the item to retrieve.
Returns
-------
Item
The requested item.
Raises
------
KeyError
If the item does not exist.
"""
return _items[item_id]
def create_item(payload: ItemCreate) -> Item:
"""
Create a new item in the data store.
A new identifier is assigned automatically. No additional validation
is performed beyond Pydantic model validation.
Parameters
----------
payload : ItemCreate
Data required to create a new item.
Returns
-------
Item
The newly created item.
"""
global _next_id
item = Item(id=_next_id, **payload.model_dump())
_items[_next_id] = item
@@ -33,6 +90,29 @@ def create_item(payload: ItemCreate) -> Item:
def update_item(item_id: int, payload: ItemCreate) -> Item:
"""
Replace an existing item in the data store.
This function performs a full replacement of the stored item.
Partial updates are not supported.
Parameters
----------
item_id : int
Identifier of the item to update.
payload : ItemCreate
New item data.
Returns
-------
Item
The updated item.
Raises
------
KeyError
If the item does not exist.
"""
if item_id not in _items:
raise KeyError(item_id)
item = Item(id=item_id, **payload.model_dump())
@@ -41,4 +121,17 @@ def update_item(item_id: int, payload: ItemCreate) -> Item:
def delete_item(item_id: int) -> None:
"""
Remove an item from the data store.
Parameters
----------
item_id : int
Identifier of the item to delete.
Raises
------
KeyError
If the item does not exist.
"""
del _items[item_id]

View File

@@ -1,3 +1,30 @@
"""
Application entry point for an OpenAPI-first model-based CRUD example service.
This module constructs a FastAPI application exclusively from an
OpenAPI specification and a handler namespace, without using
decorator-driven routing.
All HTTP routes, methods, request/response schemas, and operation
bindings are defined in the OpenAPI document referenced by
``openapi_path``. Python callables defined in the ``routes`` module are
bound to OpenAPI operations strictly via ``operationId``.
This module contains no routing logic, persistence concerns, or
framework configuration beyond application assembly.
Design guarantees:
- OpenAPI is the single source of truth
- No undocumented routes can exist
- Every OpenAPI operationId must resolve to exactly one handler
- All contract violations fail at application startup
This file is intended to be used as the ASGI entry point.
Example:
uvicorn main:app
"""
from openapi_first.app import OpenAPIFirstApp
import routes

View File

@@ -1,18 +1,50 @@
"""
Pydantic domain models for the CRUD example.
This module defines Pydantic models that represent the domain entities
used by the service. These models are referenced by the OpenAPI
specification for request and response schemas.
The models are declarative and framework-agnostic. They contain no
persistence logic, validation beyond type constraints, or business
behavior.
This module is not part of the ``openapi_first`` library API surface.
It exists solely to support the example application template.
"""
from pydantic import BaseModel
class ItemBase(BaseModel):
"""
Base domain model for an item.
Defines fields common to all item representations.
"""
name: str
price: float
class ItemCreate(ItemBase):
"""
Domain model for item creation requests.
This model is used for request bodies when creating new items.
It intentionally excludes the ``id`` field, which is assigned
by the service.
"""
pass
class Item(ItemBase):
"""
Domain model for a persisted item.
This model represents the full item state returned in responses,
including the server-assigned identifier.
"""
id: int

View File

@@ -1,5 +1,17 @@
"""
CRUD route handlers bound via OpenAPI operationId.
This module defines OpenAPI-bound operation handlers for a model-based
CRUD service. Functions in this module are bound to HTTP routes
exclusively via OpenAPI ``operationId`` values.
Handlers explicitly control HTTP response status codes to ensure runtime
behavior matches the OpenAPI contract. Domain models defined using
Pydantic are used for request and response payloads.
No routing decorators, path definitions, or implicit framework behavior
appear in this module. All routing, HTTP methods, and schemas are defined
in the OpenAPI specification.
"""
from fastapi import Response, HTTPException
@@ -15,10 +27,42 @@ from data import (
def list_items():
"""
List all items.
Implements the OpenAPI operation identified by
``operationId: list_items``.
Returns
-------
list[Item]
A list of item domain objects.
"""
return _list_items()
def get_item(item_id: int):
"""
Retrieve a single item by ID.
Implements the OpenAPI operation identified by
``operationId: get_item``.
Parameters
----------
item_id : int
Identifier of the item to retrieve.
Returns
-------
Item
The requested item.
Raises
------
HTTPException
404 if the item does not exist.
"""
try:
return _get_item(item_id)
except KeyError:
@@ -26,12 +70,53 @@ def get_item(item_id: int):
def create_item(payload: ItemCreate, response: Response):
"""
Create a new item.
Implements the OpenAPI operation identified by
``operationId: create_item``.
Parameters
----------
payload : ItemCreate
Request body describing the item to create.
response : fastapi.Response
Response object used to set the HTTP status code.
Returns
-------
Item
The newly created item.
"""
item = _create_item(payload)
response.status_code = 201
return item
def update_item(item_id: int, payload: ItemCreate):
"""
Update an existing item.
Implements the OpenAPI operation identified by
``operationId: update_item``.
Parameters
----------
item_id : int
Identifier of the item to update.
payload : ItemCreate
New item data.
Returns
-------
Item
The updated item.
Raises
------
HTTPException
404 if the item does not exist.
"""
try:
return _update_item(item_id, payload)
except KeyError:
@@ -39,6 +124,29 @@ def update_item(item_id: int, payload: ItemCreate):
def delete_item(item_id: int, response: Response):
"""
Delete an existing item.
Implements the OpenAPI operation identified by
``operationId: delete_item``.
Parameters
----------
item_id : int
Identifier of the item to delete.
response : fastapi.Response
Response object used to set the HTTP status code.
Returns
-------
None
No content.
Raises
------
HTTPException
404 if the item does not exist.
"""
try:
_delete_item(item_id)
except KeyError:

View File

@@ -3,6 +3,13 @@ End-to-end tests for the OpenAPI-first model CRUD example app.
These tests validate that all CRUD operations behave correctly
against the in-memory mock data store using Pydantic models.
- OpenAPI specification loading
- OperationId-driven route binding on the server
- OperationId-driven client invocation
- Pydantic model-based request and response handling
All CRUD operations are exercised against an in-memory mock data store
backed by Pydantic domain models.
The tests assume:
- OpenAPI-first route binding

View File

@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "openapi-first"
version = "0.0.3"
version = "0.0.4"
description = "Strict OpenAPI-first application bootstrap for FastAPI."
readme = "README.md"
requires-python = ">=3.10"
@@ -84,7 +84,7 @@ Versions = "https://git.aetoskia.com/aetos/openapi-first/tags"
packages = { find = { include = ["openapi_first*"] } }
[tool.setuptools.package-data]
fastapi_openapi_first = ["templates/**/*"]
openapi_first = ["templates/**/*"]
[tool.ruff]

View File

@@ -1,19 +0,0 @@
fastapi==0.128.0,
openapi-spec-validator==0.7.2
pyyaml==6.0.3
uvicorn==0.40.0
pydantic==2.12.5
httpx==0.28.1
# Test Packages
pytest==7.4.0
pytest-asyncio==0.21.0
pytest-cov==4.1.0
# Doc Packages
mkdocs==1.6.1
mkdocs-material==9.6.23
neoteroi-mkdocs==1.1.3
pymdown-extensions==10.16.1
mkdocstrings==1.0.0
mkdocstrings-python==2.0.1