hexastack-graphql 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.
@@ -0,0 +1,190 @@
1
+ Metadata-Version: 2.3
2
+ Name: hexastack-graphql
3
+ Version: 0.0.0
4
+ Summary: Strawberry GraphQL presentation adapter and CQRS integration for Hexastack
5
+ Author: Richard West
6
+ Author-email: Richard West <dopplereffect.us@gmail.com>
7
+ Requires-Dist: hexastack-core
8
+ Requires-Dist: hexastack-cqrs
9
+ Requires-Dist: strawberry-graphql>=0.260.0
10
+ Requires-Dist: fastapi>=0.141.1 ; extra == 'fastapi'
11
+ Requires-Dist: hexastack-fastapi ; extra == 'fastapi'
12
+ Requires-Python: >=3.13
13
+ Provides-Extra: fastapi
14
+ Description-Content-Type: text/markdown
15
+
16
+ # hexastack-graphql
17
+
18
+ > Strawberry GraphQL presentation adapter and CQRS integration for Hexastack.
19
+
20
+ [![Python 3.13+](https://img.shields.io/badge/python-3.13+-blue.svg)](https://www.python.org/downloads/)
21
+
22
+ ---
23
+
24
+ ## 1. Overview & Capabilities
25
+
26
+ `hexastack-graphql` brings the power and type-safety of [Strawberry GraphQL](https://strawberry.rocks/) into the Hexastack architecture:
27
+
28
+ - **Type-Safe GraphQL Schemas**: Native Python dataclass-based GraphQL schema definition via Strawberry.
29
+ - **CQRS Integration via Context**: Injects the `rodi.Container`, `CommandBusPort`, and `QueryBusPort` directly into Strawberry's `Info.context` (`GraphQLContext`).
30
+ - **Declarative Query & Mutation Registries**:
31
+ - `@graphql_query_type` and `@graphql_mutation_type`: Register whole type classes to be merged into root Query and Mutation types.
32
+ - `@graphql_query` and `@graphql_mutation`: Register standalone resolver functions as top-level fields.
33
+ - **Dynamic Field Resolver Feature Flagging**:
34
+ - `@feature_flag_field("flag_key", raise_error=True, fallback=...)`: Evaluates feature flags dynamically before executing field resolvers, raising a `GraphQLError` or returning a safe fallback value.
35
+ - **FastAPI Mount & GraphiQL Playground**: Seamless mounting as a `GraphQLRouter` into FastAPI applications with interactive GraphiQL playground enabled.
36
+
37
+ ---
38
+
39
+ ## 2. Package Anatomy & Key Components
40
+
41
+ ```
42
+ hexastack_graphql/
43
+ ├── domain/ # GraphQLContext, GraphQLError, SchemaBuildingError
44
+ ├── ports/ # GraphQLContextFactoryPort
45
+ ├── adapters/ # create_graphql_router, mount_graphql_router (FastAPI integration)
46
+ └── infra/
47
+ ├── bootstrap.py # GraphQLBootstrapper (order=35)
48
+ ├── config.py # HexastackGraphQLConfig
49
+ ├── decorators.py# @graphql_query, @graphql_mutation, @graphql_query_type, @graphql_mutation_type, @feature_flag_field
50
+ └── registries/ # schema.py (GraphQLSchemaRegistry)
51
+ ```
52
+
53
+ ### Key Exports
54
+
55
+ | Category | Exports |
56
+ |---|---|
57
+ | **Bootstrap** | `GraphQLBootstrapper` (order=35), `HexastackGraphQLConfig` |
58
+ | **Context & Domain** | `GraphQLContext`, `GraphQLError`, `SchemaBuildingError` |
59
+ | **Decorators** | `@graphql_query`, `@graphql_mutation`, `@graphql_query_type`, `@graphql_mutation_type`, `@feature_flag_field` |
60
+ | **FastAPI Adapters** | `create_graphql_router`, `mount_graphql_router` |
61
+ | **Registries** | `GraphQLSchemaRegistry`, `get_schema_registry` |
62
+
63
+ ---
64
+
65
+ ## 3. Monorepo & Sibling Relationships
66
+
67
+ ```mermaid
68
+ graph TD
69
+ subgraph ClientRequests ["GraphQL Client Requests"]
70
+ CLIENT["Web / Mobile GraphQL Clients"]
71
+ end
72
+
73
+ subgraph GraphQLAdapter ["hexastack-graphql"]
74
+ SCHEMA["strawberry.Schema"]
75
+ CTX["GraphQLContext (Container + Buses)"]
76
+ ROUTER["GraphQLRouter (FastAPI integration)"]
77
+ end
78
+
79
+ subgraph ApplicationLayer ["hexastack-cqrs"]
80
+ CBUS["CommandBusPort"]
81
+ QBUS["QueryBusPort"]
82
+ end
83
+
84
+ subgraph WebServer ["hexastack-fastapi"]
85
+ FASTAPI_APP["FastAPI Application"]
86
+ end
87
+
88
+ CLIENT --> ROUTER
89
+ FASTAPI_APP --> ROUTER
90
+ ROUTER --> SCHEMA
91
+ SCHEMA --> CTX
92
+ CTX -->|dispatches commands/queries to| CBUS
93
+ CTX -->|dispatches commands/queries to| QBUS
94
+ ```
95
+
96
+ ### Explicit Dependencies (Direct)
97
+ - `hexastack-core`: DI container, configuration registry, base exceptions.
98
+ - `hexastack-cqrs`: `CommandBusPort` and `QueryBusPort` for message dispatching.
99
+ - `strawberry-graphql>=0.260.0`: Core GraphQL engine and schema generator.
100
+
101
+ ### Implied / Behavioral Relationships (DI-Mediated)
102
+ - **FastAPI Auto-Mounting**: `GraphQLBootstrapper` (order=35) discovers the `FastAPI` instance created by `FastApiBootstrapper` (order=30) and attaches the `GraphQLRouter` automatically if `auto_mount_fastapi=true`.
103
+ - **CQRS Dispatching**: Field resolvers receive `info.context.query_bus` and `info.context.command_bus` to delegate execution into the CQRS pipeline.
104
+
105
+ ### Optional Integrations (Extras)
106
+ - `[fastapi]`: Installs `hexastack-fastapi` and `fastapi>=0.141.1` for HTTP routing and GraphiQL playground.
107
+
108
+ ---
109
+
110
+ ## 4. Installation
111
+
112
+ ```bash
113
+ # Standalone install
114
+ pip install hexastack-graphql
115
+
116
+ # With FastAPI integration
117
+ pip install "hexastack-graphql[fastapi]"
118
+
119
+ # Via umbrella package
120
+ pip install "hexastack[graphql]"
121
+ ```
122
+
123
+ ---
124
+
125
+ ## 5. Configuration Reference
126
+
127
+ ```toml
128
+ [hexastack.graphql]
129
+ path = "/graphql" # Route prefix for GraphQL endpoint
130
+ graphiql = true # Enable interactive GraphiQL web UI
131
+ allow_queries = true
132
+ allow_mutations = true
133
+ auto_mount_fastapi = true # Auto mount onto FastAPI application on bootstrap
134
+ title = "Hexastack GraphQL API"
135
+ ```
136
+
137
+ ---
138
+
139
+ ## 6. Quickstart Example
140
+
141
+ ```python
142
+ from dataclasses import dataclass
143
+ import strawberry
144
+ from strawberry.types import Info
145
+ from hexastack_core.infra.bootstrap import bootstrap
146
+ from hexastack_cqrs.domain.query import Query
147
+ from hexastack_cqrs.infra.decorators import query_handler
148
+ from hexastack_graphql.domain.context import GraphQLContext
149
+ from hexastack_graphql.infra.decorators import graphql_query_type
150
+
151
+
152
+ # 1. Define CQRS Query & Handler
153
+ @dataclass(frozen=True)
154
+ class GetItemQuery(Query):
155
+ item_id: str
156
+
157
+
158
+ @query_handler(GetItemQuery)
159
+ class GetItemHandler:
160
+ def __call__(self, qry: GetItemQuery) -> dict:
161
+ return {"id": qry.item_id, "name": f"Item {qry.item_id}"}
162
+
163
+
164
+ # 2. Define Strawberry GraphQL Type
165
+ @strawberry.type
166
+ class ItemType:
167
+ id: str
168
+ name: str
169
+
170
+
171
+ @graphql_query_type
172
+ class Query:
173
+ @strawberry.field
174
+ def item(self, info: Info[GraphQLContext, None], item_id: str) -> ItemType:
175
+ res = info.context.query_bus.dispatch(GetItemQuery(item_id=item_id))
176
+ return ItemType(id=res["id"], name=res["name"])
177
+
178
+
179
+ # 3. Bootstrap Runtime with GraphQL
180
+ runtime = bootstrap(packages_to_scan=[__name__])
181
+ schema = runtime.get("graphql_schema")
182
+
183
+ result = schema.execute_sync(
184
+ '{ item(itemId: "123") { id name } }',
185
+ context_value=GraphQLContext(
186
+ container=runtime.container, query_bus=runtime.get("query_bus")
187
+ ),
188
+ )
189
+ print(result.data) # {'item': {'id': '123', 'name': 'Item 123'}}
190
+ ```
@@ -0,0 +1,175 @@
1
+ # hexastack-graphql
2
+
3
+ > Strawberry GraphQL presentation adapter and CQRS integration for Hexastack.
4
+
5
+ [![Python 3.13+](https://img.shields.io/badge/python-3.13+-blue.svg)](https://www.python.org/downloads/)
6
+
7
+ ---
8
+
9
+ ## 1. Overview & Capabilities
10
+
11
+ `hexastack-graphql` brings the power and type-safety of [Strawberry GraphQL](https://strawberry.rocks/) into the Hexastack architecture:
12
+
13
+ - **Type-Safe GraphQL Schemas**: Native Python dataclass-based GraphQL schema definition via Strawberry.
14
+ - **CQRS Integration via Context**: Injects the `rodi.Container`, `CommandBusPort`, and `QueryBusPort` directly into Strawberry's `Info.context` (`GraphQLContext`).
15
+ - **Declarative Query & Mutation Registries**:
16
+ - `@graphql_query_type` and `@graphql_mutation_type`: Register whole type classes to be merged into root Query and Mutation types.
17
+ - `@graphql_query` and `@graphql_mutation`: Register standalone resolver functions as top-level fields.
18
+ - **Dynamic Field Resolver Feature Flagging**:
19
+ - `@feature_flag_field("flag_key", raise_error=True, fallback=...)`: Evaluates feature flags dynamically before executing field resolvers, raising a `GraphQLError` or returning a safe fallback value.
20
+ - **FastAPI Mount & GraphiQL Playground**: Seamless mounting as a `GraphQLRouter` into FastAPI applications with interactive GraphiQL playground enabled.
21
+
22
+ ---
23
+
24
+ ## 2. Package Anatomy & Key Components
25
+
26
+ ```
27
+ hexastack_graphql/
28
+ ├── domain/ # GraphQLContext, GraphQLError, SchemaBuildingError
29
+ ├── ports/ # GraphQLContextFactoryPort
30
+ ├── adapters/ # create_graphql_router, mount_graphql_router (FastAPI integration)
31
+ └── infra/
32
+ ├── bootstrap.py # GraphQLBootstrapper (order=35)
33
+ ├── config.py # HexastackGraphQLConfig
34
+ ├── decorators.py# @graphql_query, @graphql_mutation, @graphql_query_type, @graphql_mutation_type, @feature_flag_field
35
+ └── registries/ # schema.py (GraphQLSchemaRegistry)
36
+ ```
37
+
38
+ ### Key Exports
39
+
40
+ | Category | Exports |
41
+ |---|---|
42
+ | **Bootstrap** | `GraphQLBootstrapper` (order=35), `HexastackGraphQLConfig` |
43
+ | **Context & Domain** | `GraphQLContext`, `GraphQLError`, `SchemaBuildingError` |
44
+ | **Decorators** | `@graphql_query`, `@graphql_mutation`, `@graphql_query_type`, `@graphql_mutation_type`, `@feature_flag_field` |
45
+ | **FastAPI Adapters** | `create_graphql_router`, `mount_graphql_router` |
46
+ | **Registries** | `GraphQLSchemaRegistry`, `get_schema_registry` |
47
+
48
+ ---
49
+
50
+ ## 3. Monorepo & Sibling Relationships
51
+
52
+ ```mermaid
53
+ graph TD
54
+ subgraph ClientRequests ["GraphQL Client Requests"]
55
+ CLIENT["Web / Mobile GraphQL Clients"]
56
+ end
57
+
58
+ subgraph GraphQLAdapter ["hexastack-graphql"]
59
+ SCHEMA["strawberry.Schema"]
60
+ CTX["GraphQLContext (Container + Buses)"]
61
+ ROUTER["GraphQLRouter (FastAPI integration)"]
62
+ end
63
+
64
+ subgraph ApplicationLayer ["hexastack-cqrs"]
65
+ CBUS["CommandBusPort"]
66
+ QBUS["QueryBusPort"]
67
+ end
68
+
69
+ subgraph WebServer ["hexastack-fastapi"]
70
+ FASTAPI_APP["FastAPI Application"]
71
+ end
72
+
73
+ CLIENT --> ROUTER
74
+ FASTAPI_APP --> ROUTER
75
+ ROUTER --> SCHEMA
76
+ SCHEMA --> CTX
77
+ CTX -->|dispatches commands/queries to| CBUS
78
+ CTX -->|dispatches commands/queries to| QBUS
79
+ ```
80
+
81
+ ### Explicit Dependencies (Direct)
82
+ - `hexastack-core`: DI container, configuration registry, base exceptions.
83
+ - `hexastack-cqrs`: `CommandBusPort` and `QueryBusPort` for message dispatching.
84
+ - `strawberry-graphql>=0.260.0`: Core GraphQL engine and schema generator.
85
+
86
+ ### Implied / Behavioral Relationships (DI-Mediated)
87
+ - **FastAPI Auto-Mounting**: `GraphQLBootstrapper` (order=35) discovers the `FastAPI` instance created by `FastApiBootstrapper` (order=30) and attaches the `GraphQLRouter` automatically if `auto_mount_fastapi=true`.
88
+ - **CQRS Dispatching**: Field resolvers receive `info.context.query_bus` and `info.context.command_bus` to delegate execution into the CQRS pipeline.
89
+
90
+ ### Optional Integrations (Extras)
91
+ - `[fastapi]`: Installs `hexastack-fastapi` and `fastapi>=0.141.1` for HTTP routing and GraphiQL playground.
92
+
93
+ ---
94
+
95
+ ## 4. Installation
96
+
97
+ ```bash
98
+ # Standalone install
99
+ pip install hexastack-graphql
100
+
101
+ # With FastAPI integration
102
+ pip install "hexastack-graphql[fastapi]"
103
+
104
+ # Via umbrella package
105
+ pip install "hexastack[graphql]"
106
+ ```
107
+
108
+ ---
109
+
110
+ ## 5. Configuration Reference
111
+
112
+ ```toml
113
+ [hexastack.graphql]
114
+ path = "/graphql" # Route prefix for GraphQL endpoint
115
+ graphiql = true # Enable interactive GraphiQL web UI
116
+ allow_queries = true
117
+ allow_mutations = true
118
+ auto_mount_fastapi = true # Auto mount onto FastAPI application on bootstrap
119
+ title = "Hexastack GraphQL API"
120
+ ```
121
+
122
+ ---
123
+
124
+ ## 6. Quickstart Example
125
+
126
+ ```python
127
+ from dataclasses import dataclass
128
+ import strawberry
129
+ from strawberry.types import Info
130
+ from hexastack_core.infra.bootstrap import bootstrap
131
+ from hexastack_cqrs.domain.query import Query
132
+ from hexastack_cqrs.infra.decorators import query_handler
133
+ from hexastack_graphql.domain.context import GraphQLContext
134
+ from hexastack_graphql.infra.decorators import graphql_query_type
135
+
136
+
137
+ # 1. Define CQRS Query & Handler
138
+ @dataclass(frozen=True)
139
+ class GetItemQuery(Query):
140
+ item_id: str
141
+
142
+
143
+ @query_handler(GetItemQuery)
144
+ class GetItemHandler:
145
+ def __call__(self, qry: GetItemQuery) -> dict:
146
+ return {"id": qry.item_id, "name": f"Item {qry.item_id}"}
147
+
148
+
149
+ # 2. Define Strawberry GraphQL Type
150
+ @strawberry.type
151
+ class ItemType:
152
+ id: str
153
+ name: str
154
+
155
+
156
+ @graphql_query_type
157
+ class Query:
158
+ @strawberry.field
159
+ def item(self, info: Info[GraphQLContext, None], item_id: str) -> ItemType:
160
+ res = info.context.query_bus.dispatch(GetItemQuery(item_id=item_id))
161
+ return ItemType(id=res["id"], name=res["name"])
162
+
163
+
164
+ # 3. Bootstrap Runtime with GraphQL
165
+ runtime = bootstrap(packages_to_scan=[__name__])
166
+ schema = runtime.get("graphql_schema")
167
+
168
+ result = schema.execute_sync(
169
+ '{ item(itemId: "123") { id name } }',
170
+ context_value=GraphQLContext(
171
+ container=runtime.container, query_bus=runtime.get("query_bus")
172
+ ),
173
+ )
174
+ print(result.data) # {'item': {'id': '123', 'name': 'Item 123'}}
175
+ ```
@@ -0,0 +1,58 @@
1
+ [project]
2
+ name = "hexastack-graphql"
3
+ version = "0.0.0"
4
+ description = "Strawberry GraphQL presentation adapter and CQRS integration for Hexastack"
5
+ readme = "README.md"
6
+ requires-python = ">=3.13"
7
+ dependencies = [
8
+ "hexastack-core",
9
+ "hexastack-cqrs",
10
+ "strawberry-graphql>=0.260.0",
11
+ ]
12
+
13
+ [[project.authors]]
14
+ name = "Richard West"
15
+ email = "dopplereffect.us@gmail.com"
16
+
17
+ [project.optional-dependencies]
18
+ fastapi = [
19
+ "fastapi>=0.141.1",
20
+ "hexastack-fastapi",
21
+ ]
22
+
23
+ [project.entry-points."hexastack.bootstrappers"]
24
+ graphql = "hexastack_graphql.infra.bootstrap:GraphQLBootstrapper"
25
+
26
+ [build-system]
27
+ requires = ["uv_build>=0.12.3,<0.13.0"]
28
+ build-backend = "uv_build"
29
+
30
+ [tool.uv.sources.hexastack-core]
31
+ workspace = true
32
+
33
+ [tool.uv.sources.hexastack-cqrs]
34
+ workspace = true
35
+
36
+ [tool.uv.sources.hexastack-fastapi]
37
+ workspace = true
38
+
39
+ [tool.importlinter]
40
+ root_packages = ["hexastack_graphql"]
41
+
42
+ [[tool.importlinter.contracts]]
43
+ name = "Hexagonal architecture layer hierarchy"
44
+ type = "layers"
45
+ containers = ["hexastack_graphql"]
46
+ layers = [
47
+ "adapters",
48
+ "domain",
49
+ ]
50
+
51
+ [[tool.importlinter.contracts]]
52
+ name = "Forbidden imports for domain"
53
+ type = "forbidden"
54
+ source_modules = ["hexastack_graphql.domain"]
55
+ forbidden_modules = [
56
+ "hexastack_graphql.adapters",
57
+ "hexastack_graphql.infra",
58
+ ]
@@ -0,0 +1,53 @@
1
+ [project]
2
+ name = "hexastack-graphql"
3
+ version = "0.0.0"
4
+ description = "Strawberry GraphQL presentation adapter and CQRS integration 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
+ "hexastack-core",
12
+ "hexastack-cqrs",
13
+ "strawberry-graphql>=0.260.0",
14
+ ]
15
+
16
+ [project.optional-dependencies]
17
+ fastapi = [
18
+ "fastapi>=0.141.1",
19
+ "hexastack-fastapi",
20
+ ]
21
+
22
+ [project.entry-points."hexastack.bootstrappers"]
23
+ graphql = "hexastack_graphql.infra.bootstrap:GraphQLBootstrapper"
24
+
25
+ [build-system]
26
+ requires = ["uv_build>=0.12.3,<0.13.0"]
27
+ build-backend = "uv_build"
28
+
29
+ [tool.uv.sources]
30
+ hexastack-core = { workspace = true }
31
+ hexastack-cqrs = { workspace = true }
32
+ hexastack-fastapi = { workspace = true }
33
+
34
+ [tool.importlinter]
35
+ root_packages = ["hexastack_graphql"]
36
+
37
+ [[tool.importlinter.contracts]]
38
+ name = "Hexagonal architecture layer hierarchy"
39
+ type = "layers"
40
+ containers = ["hexastack_graphql"]
41
+ layers = [
42
+ "adapters",
43
+ "domain",
44
+ ]
45
+
46
+ [[tool.importlinter.contracts]]
47
+ name = "Forbidden imports for domain"
48
+ type = "forbidden"
49
+ source_modules = ["hexastack_graphql.domain"]
50
+ forbidden_modules = [
51
+ "hexastack_graphql.adapters",
52
+ "hexastack_graphql.infra",
53
+ ]
@@ -0,0 +1,7 @@
1
+ from hexastack_graphql import adapters, domain, infra
2
+
3
+ __all__ = [
4
+ "adapters",
5
+ "domain",
6
+ "infra",
7
+ ]
@@ -0,0 +1,122 @@
1
+ import importlib.util
2
+ from typing import Any
3
+
4
+ import strawberry
5
+ from rodi import Container
6
+
7
+ from hexastack_core.domain.exceptions import MissingDependencyError
8
+ from hexastack_cqrs.ports.buses import CommandBusPort, QueryBusPort
9
+ from hexastack_graphql.domain.context import GraphQLContext
10
+
11
+ __all__ = [
12
+ "create_graphql_router",
13
+ "mount_graphql_router",
14
+ ]
15
+
16
+
17
+ def _require_fastapi() -> None:
18
+ """Guard against missing FastAPI installation.
19
+
20
+ Raises:
21
+ MissingDependencyError: If fastapi is not installed.
22
+ """
23
+ if importlib.util.find_spec("fastapi") is None:
24
+ raise MissingDependencyError(
25
+ "fastapi is required for FastAPI GraphQL integration. "
26
+ "Install via 'pip install hexastack-graphql[fastapi]'."
27
+ )
28
+
29
+
30
+ def create_graphql_router(
31
+ schema: strawberry.Schema,
32
+ container: Container,
33
+ *,
34
+ command_bus: CommandBusPort | None = None,
35
+ query_bus: QueryBusPort | None = None,
36
+ graphiql: bool = True,
37
+ ) -> Any:
38
+ """Construct a Strawberry GraphQLRouter for FastAPI.
39
+
40
+ Notes/Architectural Intent:
41
+ Creates a FastAPI APIRouter subclass (GraphQLRouter) that dynamically
42
+ injects the rodi Container and CQRS message buses into Info.context for
43
+ every HTTP execution.
44
+
45
+ Args:
46
+ schema: Compiled strawberry.Schema instance.
47
+ container: rodi DI Container.
48
+ command_bus: Optional CommandBusPort instance.
49
+ query_bus: Optional QueryBusPort instance.
50
+ graphiql: If True, enables the GraphiQL interactive playground.
51
+
52
+ Returns:
53
+ Configured strawberry.fastapi.GraphQLRouter instance.
54
+
55
+ Raises:
56
+ MissingDependencyError: If fastapi is not installed.
57
+ """
58
+ _require_fastapi()
59
+ from starlette.requests import Request
60
+ from strawberry.fastapi import GraphQLRouter
61
+
62
+ async def get_context(request: Request) -> GraphQLContext:
63
+ # Dynamically resolve buses from container if not passed explicitly
64
+ c_bus = command_bus
65
+ if c_bus is None and container is not None:
66
+ try:
67
+ c_bus = container.resolve(CommandBusPort)
68
+ except Exception: # noqa: BLE001
69
+ c_bus = None
70
+
71
+ q_bus = query_bus
72
+ if q_bus is None and container is not None:
73
+ try:
74
+ q_bus = container.resolve(QueryBusPort)
75
+ except Exception: # noqa: BLE001
76
+ q_bus = None
77
+
78
+ ctx = GraphQLContext(
79
+ container=container,
80
+ command_bus=c_bus,
81
+ query_bus=q_bus,
82
+ )
83
+ ctx.request = request
84
+ return ctx
85
+
86
+ return GraphQLRouter(
87
+ schema=schema,
88
+ context_getter=get_context,
89
+ graphql_ide="graphiql" if graphiql else None,
90
+ )
91
+
92
+
93
+ def mount_graphql_router(
94
+ app: Any,
95
+ schema: strawberry.Schema,
96
+ container: Container,
97
+ *,
98
+ path: str = "/graphql",
99
+ graphiql: bool = True,
100
+ ) -> None:
101
+ """Mount Strawberry GraphQL router directly onto a FastAPI application instance.
102
+
103
+ Args:
104
+ app: Target FastAPI application instance.
105
+ schema: Compiled strawberry.Schema.
106
+ container: rodi DI Container.
107
+ path: Route prefix for GraphQL endpoints. Defaults to "/graphql".
108
+ graphiql: If True, enables GraphiQL playground.
109
+
110
+ Returns:
111
+ None.
112
+
113
+ Raises:
114
+ MissingDependencyError: If fastapi is not installed.
115
+ """
116
+ _require_fastapi()
117
+ router = create_graphql_router(
118
+ schema=schema,
119
+ container=container,
120
+ graphiql=graphiql,
121
+ )
122
+ app.include_router(router, prefix=path)
@@ -0,0 +1,27 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import Any
3
+
4
+ from strawberry.fastapi.context import BaseContext
5
+
6
+
7
+ @dataclass
8
+ class GraphQLContext(BaseContext):
9
+ """Execution context injected into Strawberry GraphQL resolvers.
10
+
11
+ Notes/Architectural Intent:
12
+ Carries the rodi DI container and CQRS command/query buses into
13
+ field resolvers, enabling clean dispatching from GraphQL queries
14
+ and mutations. Inherits from Strawberry's BaseContext for full
15
+ FastAPI router integration.
16
+ """
17
+
18
+ container: Any | None = None
19
+ command_bus: Any | None = None
20
+ query_bus: Any | None = None
21
+ request: Any | None = None
22
+ properties: dict[str, Any] = field(default_factory=dict)
23
+
24
+
25
+ __all__ = [
26
+ "GraphQLContext",
27
+ ]
@@ -0,0 +1,25 @@
1
+ from hexastack_core.domain.exceptions import HexastackError
2
+
3
+
4
+ class GraphQLError(HexastackError):
5
+ """Base exception for all GraphQL adapter errors.
6
+
7
+ Notes/Architectural Intent:
8
+ Inherits from HexastackError to maintain unified exception hierarchy
9
+ across core and adapter layers.
10
+ """
11
+
12
+
13
+ class SchemaBuildingError(GraphQLError):
14
+ """Exception raised when GraphQL schema construction or validation fails.
15
+
16
+ Notes/Architectural Intent:
17
+ Raised when no queries or mutations are registered, or when invalid
18
+ field definitions conflict during schema compilation.
19
+ """
20
+
21
+
22
+ __all__ = [
23
+ "GraphQLError",
24
+ "SchemaBuildingError",
25
+ ]