hexastack-fastapi 0.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of hexastack-fastapi might be problematic. Click here for more details.
- hexastack_fastapi-0.0.0/PKG-INFO +169 -0
- hexastack_fastapi-0.0.0/README.md +148 -0
- hexastack_fastapi-0.0.0/pyproject.toml +43 -0
- hexastack_fastapi-0.0.0/pyproject.toml.orig +44 -0
- hexastack_fastapi-0.0.0/src/hexastack_fastapi/__init__.py +6 -0
- hexastack_fastapi-0.0.0/src/hexastack_fastapi/adapters/__init__.py +41 -0
- hexastack_fastapi-0.0.0/src/hexastack_fastapi/adapters/app.py +118 -0
- hexastack_fastapi-0.0.0/src/hexastack_fastapi/adapters/db_session.py +160 -0
- hexastack_fastapi-0.0.0/src/hexastack_fastapi/adapters/dependencies.py +190 -0
- hexastack_fastapi-0.0.0/src/hexastack_fastapi/adapters/docs.py +80 -0
- hexastack_fastapi-0.0.0/src/hexastack_fastapi/adapters/health.py +62 -0
- hexastack_fastapi-0.0.0/src/hexastack_fastapi/adapters/routing.py +203 -0
- hexastack_fastapi-0.0.0/src/hexastack_fastapi/adapters/ui.py +491 -0
- hexastack_fastapi-0.0.0/src/hexastack_fastapi/infra/__init__.py +41 -0
- hexastack_fastapi-0.0.0/src/hexastack_fastapi/infra/autodiscovery.py +103 -0
- hexastack_fastapi-0.0.0/src/hexastack_fastapi/infra/bootstrap.py +85 -0
- hexastack_fastapi-0.0.0/src/hexastack_fastapi/infra/config.py +113 -0
- hexastack_fastapi-0.0.0/src/hexastack_fastapi/infra/decorators.py +199 -0
- hexastack_fastapi-0.0.0/src/hexastack_fastapi/infra/exception_handlers.py +60 -0
- hexastack_fastapi-0.0.0/src/hexastack_fastapi/infra/middleware/__init__.py +11 -0
- hexastack_fastapi-0.0.0/src/hexastack_fastapi/infra/middleware/correlation.py +100 -0
- hexastack_fastapi-0.0.0/src/hexastack_fastapi/infra/middleware/logging.py +95 -0
- hexastack_fastapi-0.0.0/src/hexastack_fastapi/py.typed +0 -0
- hexastack_fastapi-0.0.0/src/hexastack_fastapi/testing/__init__.py +18 -0
- hexastack_fastapi-0.0.0/src/hexastack_fastapi/testing/cursor.py +115 -0
- hexastack_fastapi-0.0.0/src/hexastack_fastapi/testing/recorder.py +238 -0
- hexastack_fastapi-0.0.0/src/hexastack_fastapi/testing/server.py +120 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: hexastack-fastapi
|
|
3
|
+
Version: 0.0.0
|
|
4
|
+
Summary: FastAPI presentation adapter for Hexastack
|
|
5
|
+
Author: Richard West
|
|
6
|
+
Author-email: Richard West <dopplereffect.us@gmail.com>
|
|
7
|
+
Requires-Dist: fastapi>=0.141.1
|
|
8
|
+
Requires-Dist: hexastack-core
|
|
9
|
+
Requires-Dist: hexastack-cqrs
|
|
10
|
+
Requires-Dist: hexastack-auth ; extra == 'auth'
|
|
11
|
+
Requires-Dist: zensical>=0.0.56 ; extra == 'docs'
|
|
12
|
+
Requires-Dist: playwright>=1.49.0 ; extra == 'testing'
|
|
13
|
+
Requires-Dist: schemathesis>=3.39.0 ; extra == 'testing'
|
|
14
|
+
Requires-Dist: nicegui>=2.0.0 ; extra == 'ui'
|
|
15
|
+
Requires-Python: >=3.13
|
|
16
|
+
Provides-Extra: auth
|
|
17
|
+
Provides-Extra: docs
|
|
18
|
+
Provides-Extra: testing
|
|
19
|
+
Provides-Extra: ui
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# hexastack-fastapi
|
|
23
|
+
|
|
24
|
+
> FastAPI presentation adapter for Hexastack: automatic CQRS routing, database session middleware, exception mapping, and health check endpoints.
|
|
25
|
+
|
|
26
|
+
[](https://www.python.org/downloads/)
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 1. Overview & Capabilities
|
|
31
|
+
|
|
32
|
+
- **Automatic CQRS Routing & Feature Gating**: Map HTTP endpoints directly to `CommandBusPort` or `QueryBusPort` using `@api_command` and `@api_query`, with native feature flag route guards (`@feature_flag_route` and `require_feature(...)`).
|
|
33
|
+
- **Decoupled Database Session Middleware**: `DbSessionMiddleware` (sync) and `AsyncDbSessionMiddleware` (async) manage session-per-request lifecycles by consuming sessionmakers from DI without a hard dependency on `hexastack-db`.
|
|
34
|
+
- **Standardized Exception Handlers**: Automatically translates domain exceptions (`EntityNotFoundError`, `UniqueConstraintViolationError`, `HexastackError`) into appropriate HTTP status codes (404, 409, 500) and structured JSON error envelopes.
|
|
35
|
+
- **Observability & Correlation Middleware**: Injects `X-Correlation-ID` headers and logs HTTP request lifecycles.
|
|
36
|
+
- **Built-in Health Checks**: Configurable `/health` and `/ready` endpoints verifying container and subsystem readiness.
|
|
37
|
+
- **NiceGUI Reactive UI & DevTools Dashboard**: Optional `[ui]` presentation adapter providing `ui_page`, `dispatch_command`, `dispatch_query`, and a zero-config interactive developer console (`mount_devtools_dashboard`) for inspecting CQRS buses, feature flags, and DI services.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 2. Package Anatomy & Key Components
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
hexastack_fastapi/
|
|
45
|
+
├── domain/ # HealthStatus, HTTP error envelope models
|
|
46
|
+
├── adapters/ # create_app, routing decorators, health endpoints, db_session middleware, dependencies, NiceGUI UI adapter
|
|
47
|
+
└── infra/ # FastApiBootstrapper (order=30), exception handlers, correlation/logging middlewares
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Key Exports
|
|
51
|
+
|
|
52
|
+
| Category | Exports |
|
|
53
|
+
|---|---|
|
|
54
|
+
| **Application Factory** | `create_app`, `FastApiBootstrapper` (order=30) |
|
|
55
|
+
| **Decorators** | `@api_command`, `@api_query`, `@feature_flag_route`, `RouteMetadata` |
|
|
56
|
+
| **Dependencies** | `get_container`, `get_pipeline`, `get_feature_flags`, `require_feature` |
|
|
57
|
+
| **Documentation Mounting** | `mount_zensical_docs`, `DocumentationNotFoundError`, `ZensicalDocsConfig` |
|
|
58
|
+
| **Exception Handlers** | `register_exception_handlers`, `domain_exception_handler` |
|
|
59
|
+
| **Middlewares** | `DbSessionMiddleware`, `AsyncDbSessionMiddleware`, `add_db_session_middleware`, `CorrelationMiddleware`, `HttpLoggingMiddleware` |
|
|
60
|
+
| **Reactive UI (NiceGUI)** | `dispatch_command`, `dispatch_query`, `mount_devtools_dashboard`, `mount_ui_app`, `ui_page` |
|
|
61
|
+
| **Routing** | `CqrsRouter`, `autodiscover_routes` |
|
|
62
|
+
| **Testing, E2E & Demo Narration** | `create_test_client`, `check_openapi_conformance`, `EphemeralServer`, `ephemeral_server`, `find_free_port`, `smart_click`, `DemoNarrator`, `VIRTUAL_CURSOR_SCRIPT` |
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 3. Monorepo & Sibling Relationships
|
|
67
|
+
|
|
68
|
+
```mermaid
|
|
69
|
+
graph TD
|
|
70
|
+
subgraph ClientRequests ["Client HTTP Inbound"]
|
|
71
|
+
HTTP["HTTP Client Requests"]
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
subgraph FastApiLayer ["hexastack-fastapi"]
|
|
75
|
+
APP["FastAPI Application"]
|
|
76
|
+
MW["Middleware (Correlation, HTTP Logging, DB Session)"]
|
|
77
|
+
ROUTER["CQRS Route Dispatcher"]
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
subgraph CQRSExecution ["hexastack-cqrs"]
|
|
81
|
+
CBUS["CommandBusPort"]
|
|
82
|
+
QBUS["QueryBusPort"]
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
subgraph DecoupledProviders ["Decoupled Providers (via DI)"]
|
|
86
|
+
DB_FACTORY["sessionmaker / async_sessionmaker (from hexastack-db)"]
|
|
87
|
+
LOG_PORT["LoggerPort (from hexastack-logging)"]
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
HTTP --> APP
|
|
91
|
+
APP --> MW
|
|
92
|
+
MW --> ROUTER
|
|
93
|
+
ROUTER -->|dispatches to| CBUS
|
|
94
|
+
ROUTER -->|dispatches to| QBUS
|
|
95
|
+
|
|
96
|
+
MW -. consumes session factory from DI .-> DB_FACTORY
|
|
97
|
+
MW -. consumes LoggerPort from DI .-> LOG_PORT
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Explicit Dependencies (Direct)
|
|
101
|
+
- `hexastack-core`: DI container, core ports, exception registry, and context propagation.
|
|
102
|
+
- `hexastack-cqrs`: `CommandBusPort` and `QueryBusPort` for message dispatching.
|
|
103
|
+
- `fastapi>=0.141.1`: Web framework and ASGI routing.
|
|
104
|
+
|
|
105
|
+
### Implied / Behavioral Relationships (DI-Mediated)
|
|
106
|
+
- **Zero-Dependency DB Session Management**: `DbSessionMiddleware` dynamically resolves SQLAlchemy `sessionmaker` from DI without directly importing `hexastack-db`.
|
|
107
|
+
- **Telemetry Integration**: `HttpLoggingMiddleware` outputs structured request telemetry through `LoggerPort`.
|
|
108
|
+
- **Exception Mapping**: Registers global exception handlers translating core domain errors into standard HTTP error responses.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## 4. Installation
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
# Standalone install
|
|
116
|
+
pip install hexastack-fastapi
|
|
117
|
+
|
|
118
|
+
# With Uvicorn development server
|
|
119
|
+
pip install "hexastack-fastapi[web]" # or: pip install "hexastack[web]"
|
|
120
|
+
|
|
121
|
+
# Via umbrella package
|
|
122
|
+
pip install "hexastack[fastapi]"
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## 5. Configuration Reference
|
|
128
|
+
|
|
129
|
+
```toml
|
|
130
|
+
[hexastack.fastapi]
|
|
131
|
+
title = "Hexastack API"
|
|
132
|
+
version = "1.0.0"
|
|
133
|
+
docs_url = "/docs"
|
|
134
|
+
openapi_url = "/openapi.json"
|
|
135
|
+
cors_origins = ["*"]
|
|
136
|
+
enable_correlation_header = true
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## 6. Quickstart Example
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
from dataclasses import dataclass
|
|
145
|
+
from fastapi.testclient import TestClient
|
|
146
|
+
from hexastack_core.infra.bootstrap import bootstrap
|
|
147
|
+
from hexastack_cqrs.domain.query import Query
|
|
148
|
+
from hexastack_cqrs.infra.decorators import query_handler
|
|
149
|
+
from hexastack_fastapi.adapters.app import create_app
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
@dataclass(frozen=True)
|
|
153
|
+
class GetGreetingQuery(Query):
|
|
154
|
+
name: str
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
@query_handler(GetGreetingQuery)
|
|
158
|
+
class GetGreetingHandler:
|
|
159
|
+
def __call__(self, qry: GetGreetingQuery) -> dict:
|
|
160
|
+
return {"message": f"Hello, {qry.name}!"}
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
runtime = bootstrap(packages_to_scan=[__name__])
|
|
164
|
+
app = create_app(runtime)
|
|
165
|
+
|
|
166
|
+
client = TestClient(app)
|
|
167
|
+
response = client.get("/health")
|
|
168
|
+
print(response.json()) # {"status": "healthy"}
|
|
169
|
+
```
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# hexastack-fastapi
|
|
2
|
+
|
|
3
|
+
> FastAPI presentation adapter for Hexastack: automatic CQRS routing, database session middleware, exception mapping, and health check endpoints.
|
|
4
|
+
|
|
5
|
+
[](https://www.python.org/downloads/)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. Overview & Capabilities
|
|
10
|
+
|
|
11
|
+
- **Automatic CQRS Routing & Feature Gating**: Map HTTP endpoints directly to `CommandBusPort` or `QueryBusPort` using `@api_command` and `@api_query`, with native feature flag route guards (`@feature_flag_route` and `require_feature(...)`).
|
|
12
|
+
- **Decoupled Database Session Middleware**: `DbSessionMiddleware` (sync) and `AsyncDbSessionMiddleware` (async) manage session-per-request lifecycles by consuming sessionmakers from DI without a hard dependency on `hexastack-db`.
|
|
13
|
+
- **Standardized Exception Handlers**: Automatically translates domain exceptions (`EntityNotFoundError`, `UniqueConstraintViolationError`, `HexastackError`) into appropriate HTTP status codes (404, 409, 500) and structured JSON error envelopes.
|
|
14
|
+
- **Observability & Correlation Middleware**: Injects `X-Correlation-ID` headers and logs HTTP request lifecycles.
|
|
15
|
+
- **Built-in Health Checks**: Configurable `/health` and `/ready` endpoints verifying container and subsystem readiness.
|
|
16
|
+
- **NiceGUI Reactive UI & DevTools Dashboard**: Optional `[ui]` presentation adapter providing `ui_page`, `dispatch_command`, `dispatch_query`, and a zero-config interactive developer console (`mount_devtools_dashboard`) for inspecting CQRS buses, feature flags, and DI services.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 2. Package Anatomy & Key Components
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
hexastack_fastapi/
|
|
24
|
+
├── domain/ # HealthStatus, HTTP error envelope models
|
|
25
|
+
├── adapters/ # create_app, routing decorators, health endpoints, db_session middleware, dependencies, NiceGUI UI adapter
|
|
26
|
+
└── infra/ # FastApiBootstrapper (order=30), exception handlers, correlation/logging middlewares
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Key Exports
|
|
30
|
+
|
|
31
|
+
| Category | Exports |
|
|
32
|
+
|---|---|
|
|
33
|
+
| **Application Factory** | `create_app`, `FastApiBootstrapper` (order=30) |
|
|
34
|
+
| **Decorators** | `@api_command`, `@api_query`, `@feature_flag_route`, `RouteMetadata` |
|
|
35
|
+
| **Dependencies** | `get_container`, `get_pipeline`, `get_feature_flags`, `require_feature` |
|
|
36
|
+
| **Documentation Mounting** | `mount_zensical_docs`, `DocumentationNotFoundError`, `ZensicalDocsConfig` |
|
|
37
|
+
| **Exception Handlers** | `register_exception_handlers`, `domain_exception_handler` |
|
|
38
|
+
| **Middlewares** | `DbSessionMiddleware`, `AsyncDbSessionMiddleware`, `add_db_session_middleware`, `CorrelationMiddleware`, `HttpLoggingMiddleware` |
|
|
39
|
+
| **Reactive UI (NiceGUI)** | `dispatch_command`, `dispatch_query`, `mount_devtools_dashboard`, `mount_ui_app`, `ui_page` |
|
|
40
|
+
| **Routing** | `CqrsRouter`, `autodiscover_routes` |
|
|
41
|
+
| **Testing, E2E & Demo Narration** | `create_test_client`, `check_openapi_conformance`, `EphemeralServer`, `ephemeral_server`, `find_free_port`, `smart_click`, `DemoNarrator`, `VIRTUAL_CURSOR_SCRIPT` |
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## 3. Monorepo & Sibling Relationships
|
|
46
|
+
|
|
47
|
+
```mermaid
|
|
48
|
+
graph TD
|
|
49
|
+
subgraph ClientRequests ["Client HTTP Inbound"]
|
|
50
|
+
HTTP["HTTP Client Requests"]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
subgraph FastApiLayer ["hexastack-fastapi"]
|
|
54
|
+
APP["FastAPI Application"]
|
|
55
|
+
MW["Middleware (Correlation, HTTP Logging, DB Session)"]
|
|
56
|
+
ROUTER["CQRS Route Dispatcher"]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
subgraph CQRSExecution ["hexastack-cqrs"]
|
|
60
|
+
CBUS["CommandBusPort"]
|
|
61
|
+
QBUS["QueryBusPort"]
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
subgraph DecoupledProviders ["Decoupled Providers (via DI)"]
|
|
65
|
+
DB_FACTORY["sessionmaker / async_sessionmaker (from hexastack-db)"]
|
|
66
|
+
LOG_PORT["LoggerPort (from hexastack-logging)"]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
HTTP --> APP
|
|
70
|
+
APP --> MW
|
|
71
|
+
MW --> ROUTER
|
|
72
|
+
ROUTER -->|dispatches to| CBUS
|
|
73
|
+
ROUTER -->|dispatches to| QBUS
|
|
74
|
+
|
|
75
|
+
MW -. consumes session factory from DI .-> DB_FACTORY
|
|
76
|
+
MW -. consumes LoggerPort from DI .-> LOG_PORT
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Explicit Dependencies (Direct)
|
|
80
|
+
- `hexastack-core`: DI container, core ports, exception registry, and context propagation.
|
|
81
|
+
- `hexastack-cqrs`: `CommandBusPort` and `QueryBusPort` for message dispatching.
|
|
82
|
+
- `fastapi>=0.141.1`: Web framework and ASGI routing.
|
|
83
|
+
|
|
84
|
+
### Implied / Behavioral Relationships (DI-Mediated)
|
|
85
|
+
- **Zero-Dependency DB Session Management**: `DbSessionMiddleware` dynamically resolves SQLAlchemy `sessionmaker` from DI without directly importing `hexastack-db`.
|
|
86
|
+
- **Telemetry Integration**: `HttpLoggingMiddleware` outputs structured request telemetry through `LoggerPort`.
|
|
87
|
+
- **Exception Mapping**: Registers global exception handlers translating core domain errors into standard HTTP error responses.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## 4. Installation
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# Standalone install
|
|
95
|
+
pip install hexastack-fastapi
|
|
96
|
+
|
|
97
|
+
# With Uvicorn development server
|
|
98
|
+
pip install "hexastack-fastapi[web]" # or: pip install "hexastack[web]"
|
|
99
|
+
|
|
100
|
+
# Via umbrella package
|
|
101
|
+
pip install "hexastack[fastapi]"
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## 5. Configuration Reference
|
|
107
|
+
|
|
108
|
+
```toml
|
|
109
|
+
[hexastack.fastapi]
|
|
110
|
+
title = "Hexastack API"
|
|
111
|
+
version = "1.0.0"
|
|
112
|
+
docs_url = "/docs"
|
|
113
|
+
openapi_url = "/openapi.json"
|
|
114
|
+
cors_origins = ["*"]
|
|
115
|
+
enable_correlation_header = true
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## 6. Quickstart Example
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
from dataclasses import dataclass
|
|
124
|
+
from fastapi.testclient import TestClient
|
|
125
|
+
from hexastack_core.infra.bootstrap import bootstrap
|
|
126
|
+
from hexastack_cqrs.domain.query import Query
|
|
127
|
+
from hexastack_cqrs.infra.decorators import query_handler
|
|
128
|
+
from hexastack_fastapi.adapters.app import create_app
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
@dataclass(frozen=True)
|
|
132
|
+
class GetGreetingQuery(Query):
|
|
133
|
+
name: str
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@query_handler(GetGreetingQuery)
|
|
137
|
+
class GetGreetingHandler:
|
|
138
|
+
def __call__(self, qry: GetGreetingQuery) -> dict:
|
|
139
|
+
return {"message": f"Hello, {qry.name}!"}
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
runtime = bootstrap(packages_to_scan=[__name__])
|
|
143
|
+
app = create_app(runtime)
|
|
144
|
+
|
|
145
|
+
client = TestClient(app)
|
|
146
|
+
response = client.get("/health")
|
|
147
|
+
print(response.json()) # {"status": "healthy"}
|
|
148
|
+
```
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "hexastack-fastapi"
|
|
3
|
+
version = "0.0.0"
|
|
4
|
+
description = "FastAPI presentation adapter for Hexastack"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.13"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"fastapi>=0.141.1",
|
|
9
|
+
"hexastack-core",
|
|
10
|
+
"hexastack-cqrs",
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
[[project.authors]]
|
|
14
|
+
name = "Richard West"
|
|
15
|
+
email = "dopplereffect.us@gmail.com"
|
|
16
|
+
|
|
17
|
+
[project.optional-dependencies]
|
|
18
|
+
auth = ["hexastack-auth"]
|
|
19
|
+
docs = ["zensical>=0.0.56"]
|
|
20
|
+
testing = [
|
|
21
|
+
"playwright>=1.49.0",
|
|
22
|
+
"schemathesis>=3.39.0",
|
|
23
|
+
]
|
|
24
|
+
ui = ["nicegui>=2.0.0"]
|
|
25
|
+
|
|
26
|
+
[project.entry-points."hexastack.bootstrappers"]
|
|
27
|
+
fastapi = "hexastack_fastapi.infra.bootstrap:FastApiBootstrapper"
|
|
28
|
+
|
|
29
|
+
[build-system]
|
|
30
|
+
requires = ["uv_build>=0.12.3,<0.13.0"]
|
|
31
|
+
build-backend = "uv_build"
|
|
32
|
+
|
|
33
|
+
[tool.uv.sources.hexastack-auth]
|
|
34
|
+
workspace = true
|
|
35
|
+
|
|
36
|
+
[tool.uv.sources.hexastack-core]
|
|
37
|
+
workspace = true
|
|
38
|
+
|
|
39
|
+
[tool.uv.sources.hexastack-cqrs]
|
|
40
|
+
workspace = true
|
|
41
|
+
|
|
42
|
+
[tool.importlinter]
|
|
43
|
+
root_packages = ["hexastack_fastapi"]
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "hexastack-fastapi"
|
|
3
|
+
version = "0.0.0"
|
|
4
|
+
description = "FastAPI presentation adapter for Hexastack"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "Richard West", email = "dopplereffect.us@gmail.com" }
|
|
8
|
+
]
|
|
9
|
+
requires-python = ">=3.13"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"fastapi>=0.141.1",
|
|
12
|
+
"hexastack-core",
|
|
13
|
+
"hexastack-cqrs",
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
[project.optional-dependencies]
|
|
17
|
+
auth = [
|
|
18
|
+
"hexastack-auth",
|
|
19
|
+
]
|
|
20
|
+
docs = [
|
|
21
|
+
"zensical>=0.0.56",
|
|
22
|
+
]
|
|
23
|
+
testing = [
|
|
24
|
+
"playwright>=1.49.0",
|
|
25
|
+
"schemathesis>=3.39.0",
|
|
26
|
+
]
|
|
27
|
+
ui = [
|
|
28
|
+
"nicegui>=2.0.0",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.entry-points."hexastack.bootstrappers"]
|
|
32
|
+
fastapi = "hexastack_fastapi.infra.bootstrap:FastApiBootstrapper"
|
|
33
|
+
|
|
34
|
+
[build-system]
|
|
35
|
+
requires = ["uv_build>=0.12.3,<0.13.0"]
|
|
36
|
+
build-backend = "uv_build"
|
|
37
|
+
|
|
38
|
+
[tool.uv.sources]
|
|
39
|
+
hexastack-auth = { workspace = true }
|
|
40
|
+
hexastack-core = { workspace = true }
|
|
41
|
+
hexastack-cqrs = { workspace = true }
|
|
42
|
+
|
|
43
|
+
[tool.importlinter]
|
|
44
|
+
root_packages = ["hexastack_fastapi"]
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from hexastack_fastapi.adapters.app import create_fastapi_app
|
|
2
|
+
from hexastack_fastapi.adapters.dependencies import (
|
|
3
|
+
check_openapi_conformance,
|
|
4
|
+
create_test_client,
|
|
5
|
+
get_container,
|
|
6
|
+
get_feature_flags,
|
|
7
|
+
get_pipeline,
|
|
8
|
+
require_feature,
|
|
9
|
+
)
|
|
10
|
+
from hexastack_fastapi.adapters.docs import (
|
|
11
|
+
DocumentationNotFoundError,
|
|
12
|
+
mount_zensical_docs,
|
|
13
|
+
)
|
|
14
|
+
from hexastack_fastapi.adapters.health import create_health_router
|
|
15
|
+
from hexastack_fastapi.adapters.routing import CqrsRouter
|
|
16
|
+
from hexastack_fastapi.adapters.ui import (
|
|
17
|
+
dispatch_command,
|
|
18
|
+
dispatch_query,
|
|
19
|
+
mount_devtools_dashboard,
|
|
20
|
+
mount_ui_app,
|
|
21
|
+
ui_page,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
"check_openapi_conformance",
|
|
26
|
+
"CqrsRouter",
|
|
27
|
+
"create_fastapi_app",
|
|
28
|
+
"create_health_router",
|
|
29
|
+
"create_test_client",
|
|
30
|
+
"dispatch_command",
|
|
31
|
+
"dispatch_query",
|
|
32
|
+
"DocumentationNotFoundError",
|
|
33
|
+
"get_container",
|
|
34
|
+
"get_feature_flags",
|
|
35
|
+
"get_pipeline",
|
|
36
|
+
"mount_devtools_dashboard",
|
|
37
|
+
"mount_ui_app",
|
|
38
|
+
"mount_zensical_docs",
|
|
39
|
+
"require_feature",
|
|
40
|
+
"ui_page",
|
|
41
|
+
]
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
from contextlib import asynccontextmanager
|
|
2
|
+
|
|
3
|
+
from fastapi import FastAPI
|
|
4
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
5
|
+
from rodi import Container
|
|
6
|
+
|
|
7
|
+
from hexastack_core.infra.registries.exception import ExceptionRegistry
|
|
8
|
+
from hexastack_core.ports.logging import LoggingPort
|
|
9
|
+
from hexastack_cqrs.infra.pipeline import ExecutionPipeline
|
|
10
|
+
from hexastack_fastapi.adapters.docs import mount_zensical_docs
|
|
11
|
+
from hexastack_fastapi.adapters.health import create_health_router
|
|
12
|
+
from hexastack_fastapi.infra.config import HexastackFastApiConfig
|
|
13
|
+
from hexastack_fastapi.infra.exception_handlers import (
|
|
14
|
+
register_exception_handlers,
|
|
15
|
+
)
|
|
16
|
+
from hexastack_fastapi.infra.middleware.correlation import (
|
|
17
|
+
CorrelationHttpMiddleware,
|
|
18
|
+
)
|
|
19
|
+
from hexastack_fastapi.infra.middleware.logging import (
|
|
20
|
+
RequestLoggingHttpMiddleware,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
"create_fastapi_app",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def create_fastapi_app(
|
|
29
|
+
config: HexastackFastApiConfig | None = None,
|
|
30
|
+
container: Container | None = None,
|
|
31
|
+
pipeline: ExecutionPipeline | None = None,
|
|
32
|
+
exception_registry: ExceptionRegistry | None = None,
|
|
33
|
+
) -> FastAPI:
|
|
34
|
+
"""Factory creating and configuring a FastAPI application integrated with Hexastack.
|
|
35
|
+
|
|
36
|
+
Notes/Architectural Intent:
|
|
37
|
+
Assembles FastAPI instance with OpenAPI documentation metadata, CORS middleware,
|
|
38
|
+
Correlation ID ASGI middleware, access logging, health check probes, Zensical docs mounting,
|
|
39
|
+
unified exception mapping, and DI container lifecycle management.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
config: Optional HexastackFastApiConfig instance.
|
|
43
|
+
container: Optional rodi Container instance.
|
|
44
|
+
pipeline: Optional ExecutionPipeline instance.
|
|
45
|
+
exception_registry: Optional ExceptionRegistry for domain error mapping.
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
Configured FastAPI application instance.
|
|
49
|
+
|
|
50
|
+
Raises:
|
|
51
|
+
None.
|
|
52
|
+
"""
|
|
53
|
+
cfg = config or HexastackFastApiConfig()
|
|
54
|
+
|
|
55
|
+
@asynccontextmanager
|
|
56
|
+
async def lifespan(app: FastAPI):
|
|
57
|
+
yield
|
|
58
|
+
# Teardown background resources
|
|
59
|
+
if container is not None and LoggingPort in container:
|
|
60
|
+
logger = container.resolve(LoggingPort)
|
|
61
|
+
close_fn = getattr(logger, "close", None)
|
|
62
|
+
if callable(close_fn):
|
|
63
|
+
close_fn()
|
|
64
|
+
|
|
65
|
+
app = FastAPI(
|
|
66
|
+
title=cfg.title,
|
|
67
|
+
version=cfg.version,
|
|
68
|
+
description=cfg.description,
|
|
69
|
+
docs_url=cfg.docs_url,
|
|
70
|
+
redoc_url=cfg.redoc_url,
|
|
71
|
+
openapi_url=cfg.openapi_url,
|
|
72
|
+
lifespan=lifespan,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
# Attach container and pipeline to application state
|
|
76
|
+
if container is not None:
|
|
77
|
+
app.state.container = container
|
|
78
|
+
if pipeline is not None:
|
|
79
|
+
app.state.pipeline = pipeline
|
|
80
|
+
|
|
81
|
+
# Attach CORS middleware if enabled
|
|
82
|
+
if cfg.cors.enable:
|
|
83
|
+
app.add_middleware(
|
|
84
|
+
CORSMiddleware,
|
|
85
|
+
allow_origins=cfg.cors.allow_origins,
|
|
86
|
+
allow_credentials=cfg.cors.allow_credentials,
|
|
87
|
+
allow_methods=cfg.cors.allow_methods,
|
|
88
|
+
allow_headers=cfg.cors.allow_headers,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
# Attach request logging middleware if enabled
|
|
92
|
+
if cfg.logging.enable:
|
|
93
|
+
app.add_middleware(
|
|
94
|
+
RequestLoggingHttpMiddleware,
|
|
95
|
+
config=cfg,
|
|
96
|
+
container=container,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
# Attach correlation middleware
|
|
100
|
+
app.add_middleware(CorrelationHttpMiddleware, config=cfg)
|
|
101
|
+
|
|
102
|
+
# Register unified exception handlers
|
|
103
|
+
register_exception_handlers(app, exception_registry=exception_registry)
|
|
104
|
+
|
|
105
|
+
# Mount health and readiness endpoints if enabled
|
|
106
|
+
if cfg.health.enable:
|
|
107
|
+
health_router = create_health_router(container=container, config=cfg.health)
|
|
108
|
+
app.include_router(health_router)
|
|
109
|
+
|
|
110
|
+
# Mount Zensical documentation site if enabled
|
|
111
|
+
if cfg.zensical.enable:
|
|
112
|
+
mount_zensical_docs(
|
|
113
|
+
app=app,
|
|
114
|
+
path=cfg.zensical.path,
|
|
115
|
+
site_dir=cfg.zensical.site_dir,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
return app
|