init openapi_first

This commit is contained in:
2026-01-10 17:21:21 +05:30
parent 76e2599903
commit b88ecbd7c5
5 changed files with 542 additions and 0 deletions

72
openapi_first/errors.py Normal file
View File

@@ -0,0 +1,72 @@
"""
fastapi_openapi_first.errors
============================
Custom exceptions for OpenAPI-first FastAPI applications.
This module defines a small hierarchy of explicit, intention-revealing
exceptions used to signal contract violations between an OpenAPI
specification and its Python implementation.
Design principles
-----------------
- Errors represent *programmer mistakes*, not runtime conditions.
- All errors are raised during application startup.
- Messages are actionable and suitable for CI/CD output.
- Exceptions are explicit rather than reused from generic built-ins.
These errors should normally cause immediate application failure.
"""
class OpenAPIFirstError(Exception):
"""
Base exception for all OpenAPI-first enforcement errors.
This exception exists to allow callers, test suites, and CI pipelines
to catch and distinguish OpenAPI contract violations from unrelated
runtime errors.
All exceptions raised by the OpenAPI-first core should inherit from
this type.
"""
pass
class MissingOperationHandler(OpenAPIFirstError):
"""
Raised when an OpenAPI operation cannot be resolved to a handler.
This error occurs when:
- An OpenAPI operation does not define an operationId, or
- An operationId is defined but no matching function exists in the
provided routes module.
This represents a violation of the OpenAPI-first contract and
indicates that the specification and implementation are out of sync.
"""
def __init__(self, *, path: str, method: str, operation_id: str | None = None):
"""
Parameters
----------
path : str
The HTTP path declared in the OpenAPI specification.
method : str
The HTTP method (as declared in the OpenAPI spec).
operation_id : str, optional
The operationId declared in the OpenAPI spec, if present.
"""
if operation_id:
message = (
f"Missing handler for operationId '{operation_id}' "
f"({method.upper()} {path})"
)
else:
message = (
f"Missing operationId for operation "
f"({method.upper()} {path})"
)
super().__init__(message)