graphql-api 1.4.19__tar.gz → 1.4.20__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.
- graphql_api-1.4.20/.github/workflows/pages.yml +77 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/PKG-INFO +58 -11
- {graphql_api-1.4.19 → graphql_api-1.4.20}/README.md +57 -10
- graphql_api-1.4.20/VERSION +1 -0
- graphql_api-1.4.20/docs/README.md +81 -0
- graphql_api-1.4.20/docs/content/_index.md +71 -0
- graphql_api-1.4.20/docs/content/docs/_index.md +38 -0
- {graphql_api-1.4.19/docs_md → graphql_api-1.4.20/docs/content/docs}/advanced.md +25 -13
- graphql_api-1.4.20/docs/content/docs/api-reference.md +551 -0
- {graphql_api-1.4.19/docs_md → graphql_api-1.4.20/docs/content/docs}/async-and-subscriptions.md +79 -11
- graphql_api-1.4.20/docs/content/docs/contributing.md +442 -0
- {graphql_api-1.4.19/docs_md → graphql_api-1.4.20/docs/content/docs}/defining-schemas.md +27 -5
- graphql_api-1.4.20/docs/content/docs/examples.md +528 -0
- {graphql_api-1.4.19/docs_md → graphql_api-1.4.20/docs/content/docs}/federation.md +8 -0
- {graphql_api-1.4.19/docs_md → graphql_api-1.4.20/docs/content/docs}/getting-started.md +5 -0
- {graphql_api-1.4.19/docs_md → graphql_api-1.4.20/docs/content/docs}/pydantic-and-dataclasses.md +8 -0
- graphql_api-1.4.20/docs/hugo.toml +86 -0
- graphql_api-1.4.20/docs/index.md +212 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/graphql_api/api.py +137 -13
- {graphql_api-1.4.19 → graphql_api-1.4.20}/graphql_api/mapper.py +36 -4
- {graphql_api-1.4.19 → graphql_api-1.4.20}/graphql_api.egg-info/PKG-INFO +58 -11
- {graphql_api-1.4.19 → graphql_api-1.4.20}/graphql_api.egg-info/SOURCES.txt +17 -19
- {graphql_api-1.4.19 → graphql_api-1.4.20}/tests/test_async.py +2 -1
- {graphql_api-1.4.19 → graphql_api-1.4.20}/tests/test_calculator.py +5 -5
- {graphql_api-1.4.19 → graphql_api-1.4.20}/tests/test_custom_types.py +13 -13
- {graphql_api-1.4.19 → graphql_api-1.4.20}/tests/test_dataclass.py +7 -7
- {graphql_api-1.4.19 → graphql_api-1.4.20}/tests/test_directives.py +11 -11
- {graphql_api-1.4.19 → graphql_api-1.4.20}/tests/test_docstrings.py +10 -10
- {graphql_api-1.4.19 → graphql_api-1.4.20}/tests/test_error.py +6 -6
- {graphql_api-1.4.19 → graphql_api-1.4.20}/tests/test_federation.py +4 -6
- {graphql_api-1.4.19 → graphql_api-1.4.20}/tests/test_federation_example.py +8 -8
- {graphql_api-1.4.19 → graphql_api-1.4.20}/tests/test_filtering.py +39 -38
- {graphql_api-1.4.19 → graphql_api-1.4.20}/tests/test_graphql.py +58 -61
- {graphql_api-1.4.19 → graphql_api-1.4.20}/tests/test_middleware.py +3 -3
- {graphql_api-1.4.19 → graphql_api-1.4.20}/tests/test_pydantic.py +22 -22
- {graphql_api-1.4.19 → graphql_api-1.4.20}/tests/test_relay.py +1 -1
- {graphql_api-1.4.19 → graphql_api-1.4.20}/tests/test_remote.py +62 -76
- {graphql_api-1.4.19 → graphql_api-1.4.20}/tests/test_schema.py +10 -11
- {graphql_api-1.4.19 → graphql_api-1.4.20}/tests/test_subscriptions.py +10 -10
- graphql_api-1.4.20/tests/test_unified_vs_explicit_schema.py +241 -0
- graphql_api-1.4.19/VERSION +0 -1
- graphql_api-1.4.19/docs/_static/favicon.ico +0 -0
- graphql_api-1.4.19/docs/_static/logo.png +0 -0
- graphql_api-1.4.19/docs/_templates/sidebarlogo.html +0 -7
- graphql_api-1.4.19/docs/conf.py +0 -39
- graphql_api-1.4.19/docs/images/python_to_graphql.png +0 -0
- graphql_api-1.4.19/docs/images/schema_structure.png +0 -0
- graphql_api-1.4.19/docs/index.rst +0 -107
- graphql_api-1.4.19/docs/installation.rst +0 -25
- graphql_api-1.4.19/docs/quickstart.rst +0 -431
- graphql_api-1.4.19/docs/schemas.rst +0 -405
- graphql_api-1.4.19/docs/types.rst +0 -140
- graphql_api-1.4.19/docs_md/index.md +0 -14
- {graphql_api-1.4.19 → graphql_api-1.4.20}/.github/workflows/python-package.yml +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/.gitignore +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/.vscode/settings.json +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/LICENSE +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/graphql_api/__init__.py +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/graphql_api/context.py +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/graphql_api/dataclass_mapping.py +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/graphql_api/decorators.py +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/graphql_api/directives.py +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/graphql_api/error.py +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/graphql_api/exception.py +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/graphql_api/executor.py +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/graphql_api/federation/__init__.py +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/graphql_api/federation/directives.py +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/graphql_api/federation/federation.py +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/graphql_api/federation/types.py +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/graphql_api/middleware.py +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/graphql_api/pydantic.py +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/graphql_api/reduce.py +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/graphql_api/relay.py +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/graphql_api/remote.py +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/graphql_api/schema.py +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/graphql_api/types.py +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/graphql_api/utils.py +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/graphql_api.egg-info/dependency_links.txt +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/graphql_api.egg-info/requires.txt +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/graphql_api.egg-info/top_level.txt +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/pyproject.toml +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/setup.cfg +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/tests/__init__.py +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/tests/test_federation_example.graphql +0 -0
- {graphql_api-1.4.19 → graphql_api-1.4.20}/uv.lock +0 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
name: Deploy Hugo site to GitHub Pages
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ main ]
|
|
6
|
+
paths: [ 'docs/**' ]
|
|
7
|
+
pull_request:
|
|
8
|
+
branches: [ main ]
|
|
9
|
+
paths: [ 'docs/**' ]
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
pages: write
|
|
15
|
+
id-token: write
|
|
16
|
+
|
|
17
|
+
concurrency:
|
|
18
|
+
group: "pages"
|
|
19
|
+
cancel-in-progress: false
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
build:
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
env:
|
|
25
|
+
HUGO_VERSION: 0.146.0
|
|
26
|
+
steps:
|
|
27
|
+
- name: Checkout
|
|
28
|
+
uses: actions/checkout@v4
|
|
29
|
+
with:
|
|
30
|
+
submodules: recursive
|
|
31
|
+
fetch-depth: 0
|
|
32
|
+
- name: Install Hugo CLI
|
|
33
|
+
run: |
|
|
34
|
+
wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \
|
|
35
|
+
&& sudo dpkg -i ${{ runner.temp }}/hugo.deb
|
|
36
|
+
- name: Install Dart Sass
|
|
37
|
+
run: sudo snap install dart-sass
|
|
38
|
+
- name: Setup Pages
|
|
39
|
+
id: pages
|
|
40
|
+
uses: actions/configure-pages@v4
|
|
41
|
+
with:
|
|
42
|
+
enablement: true
|
|
43
|
+
- name: Install Node.js dependencies
|
|
44
|
+
working-directory: ./docs
|
|
45
|
+
run: "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true"
|
|
46
|
+
- name: Setup Hugo Book theme
|
|
47
|
+
working-directory: ./docs
|
|
48
|
+
run: |
|
|
49
|
+
if [ ! -d "themes/hugo-book" ]; then
|
|
50
|
+
git clone --depth 1 https://github.com/alex-shpak/hugo-book.git themes/hugo-book
|
|
51
|
+
fi
|
|
52
|
+
- name: Build with Hugo
|
|
53
|
+
env:
|
|
54
|
+
HUGO_ENVIRONMENT: production
|
|
55
|
+
HUGO_ENV: production
|
|
56
|
+
working-directory: ./docs
|
|
57
|
+
run: |
|
|
58
|
+
hugo \
|
|
59
|
+
--gc \
|
|
60
|
+
--minify \
|
|
61
|
+
--baseURL "${{ steps.pages.outputs.base_url }}/"
|
|
62
|
+
- name: Upload artifact
|
|
63
|
+
uses: actions/upload-pages-artifact@v3
|
|
64
|
+
with:
|
|
65
|
+
path: ./docs/public
|
|
66
|
+
|
|
67
|
+
deploy:
|
|
68
|
+
environment:
|
|
69
|
+
name: github-pages
|
|
70
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
71
|
+
runs-on: ubuntu-latest
|
|
72
|
+
needs: build
|
|
73
|
+
if: github.ref == 'refs/heads/main'
|
|
74
|
+
steps:
|
|
75
|
+
- name: Deploy to GitHub Pages
|
|
76
|
+
id: deployment
|
|
77
|
+
uses: actions/deploy-pages@v4
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: graphql_api
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.20
|
|
4
4
|
Summary: A framework for building Python GraphQL APIs.
|
|
5
5
|
Author-email: Robert Parker <rob@parob.com>
|
|
6
6
|
License: MIT
|
|
@@ -37,6 +37,7 @@ A powerful and intuitive Python library for building GraphQL APIs, designed with
|
|
|
37
37
|
|
|
38
38
|
- **Decorator-Based Schema:** Define your GraphQL schema declaratively using simple and intuitive decorators.
|
|
39
39
|
- **Type Hinting:** Automatically converts Python type hints into GraphQL types.
|
|
40
|
+
- **Implicit Type Inference:** Automatically maps Pydantic models, dataclasses, and classes with fields - no explicit decorators needed.
|
|
40
41
|
- **Pydantic & Dataclass Support:** Seamlessly use Pydantic and Dataclass models as GraphQL types.
|
|
41
42
|
- **Asynchronous Execution:** Full support for `async` and `await` for high-performance, non-blocking resolvers.
|
|
42
43
|
- **Apollo Federation:** Built-in support for creating federated services.
|
|
@@ -109,6 +110,7 @@ class Book(BaseModel):
|
|
|
109
110
|
title: str
|
|
110
111
|
author: str
|
|
111
112
|
|
|
113
|
+
@api.type(is_root_type=True)
|
|
112
114
|
class BookAPI:
|
|
113
115
|
@api.field
|
|
114
116
|
def get_books(self) -> List[Book]:
|
|
@@ -117,7 +119,7 @@ class BookAPI:
|
|
|
117
119
|
Book(title="1984", author="George Orwell"),
|
|
118
120
|
]
|
|
119
121
|
|
|
120
|
-
api = GraphQLAPI(
|
|
122
|
+
api = GraphQLAPI()
|
|
121
123
|
|
|
122
124
|
graphql_query = """
|
|
123
125
|
query {
|
|
@@ -140,13 +142,14 @@ Define async resolvers for non-blocking I/O operations.
|
|
|
140
142
|
import asyncio
|
|
141
143
|
from graphql_api.api import GraphQLAPI
|
|
142
144
|
|
|
145
|
+
@api.type(is_root_type=True)
|
|
143
146
|
class AsyncAPI:
|
|
144
147
|
@api.field
|
|
145
148
|
async def fetch_data(self) -> str:
|
|
146
149
|
await asyncio.sleep(1)
|
|
147
150
|
return "Data fetched successfully!"
|
|
148
151
|
|
|
149
|
-
api = GraphQLAPI(
|
|
152
|
+
api = GraphQLAPI()
|
|
150
153
|
|
|
151
154
|
# To execute async queries, you'll need an async executor
|
|
152
155
|
# or to run it within an async context.
|
|
@@ -167,11 +170,11 @@ if __name__ == "__main__":
|
|
|
167
170
|
|
|
168
171
|
### Mutations with Dataclasses
|
|
169
172
|
|
|
170
|
-
Use dataclasses to define the structure of your
|
|
173
|
+
Use dataclasses to define the structure of your data, and mark fields as mutable to automatically separate them into the GraphQL Mutation type.
|
|
171
174
|
|
|
172
175
|
```python
|
|
173
176
|
from dataclasses import dataclass
|
|
174
|
-
from graphql_api.api import GraphQLAPI
|
|
177
|
+
from graphql_api.api import GraphQLAPI
|
|
175
178
|
|
|
176
179
|
@dataclass
|
|
177
180
|
class User:
|
|
@@ -181,22 +184,66 @@ class User:
|
|
|
181
184
|
# A simple in-memory database
|
|
182
185
|
db = {1: User(id=1, name="Alice")}
|
|
183
186
|
|
|
187
|
+
api = GraphQLAPI()
|
|
188
|
+
|
|
189
|
+
@api.type(is_root_type=True)
|
|
184
190
|
class Root:
|
|
185
|
-
@field
|
|
191
|
+
@api.field
|
|
186
192
|
def get_user(self, user_id: int) -> User:
|
|
187
193
|
return db.get(user_id)
|
|
188
194
|
|
|
189
|
-
|
|
190
|
-
@field
|
|
195
|
+
@api.field(mutable=True)
|
|
191
196
|
def add_user(self, user_id: int, name: str) -> User:
|
|
192
197
|
new_user = User(id=user_id, name=name)
|
|
193
198
|
db[user_id] = new_user
|
|
194
199
|
return new_user
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
GraphQL automatically separates queries and mutations - you don't need separate classes. Fields marked with `mutable=True` are placed in the Mutation type, while regular fields go in the Query type. Fields with `AsyncGenerator` return types are automatically detected as subscriptions. This automatic mapping means you can define all your operations in a single class and let `graphql-api` handle the schema organization for you.
|
|
203
|
+
|
|
204
|
+
## Two Approaches for Complex Schemas
|
|
205
|
+
|
|
206
|
+
`graphql-api` supports two approaches for organizing your GraphQL schema:
|
|
207
|
+
|
|
208
|
+
### Single Root Type (Recommended)
|
|
209
|
+
```python
|
|
210
|
+
@api.type(is_root_type=True)
|
|
211
|
+
class Root:
|
|
212
|
+
@api.field
|
|
213
|
+
def query_field(self) -> str: ...
|
|
214
|
+
|
|
215
|
+
@api.field(mutable=True)
|
|
216
|
+
def mutation_field(self) -> str: ...
|
|
217
|
+
|
|
218
|
+
@api.field
|
|
219
|
+
async def subscription_field(self) -> AsyncGenerator[str, None]: ...
|
|
220
|
+
|
|
221
|
+
api = GraphQLAPI(root_type=Root)
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Explicit Types
|
|
225
|
+
```python
|
|
226
|
+
@api.type
|
|
227
|
+
class Query:
|
|
228
|
+
@api.field
|
|
229
|
+
def query_field(self) -> str: ...
|
|
230
|
+
|
|
231
|
+
@api.type
|
|
232
|
+
class Mutation:
|
|
233
|
+
@api.field
|
|
234
|
+
def mutation_field(self) -> str: ...
|
|
235
|
+
|
|
236
|
+
@api.type
|
|
237
|
+
class Subscription:
|
|
238
|
+
@api.field
|
|
239
|
+
async def subscription_field(self) -> AsyncGenerator[str, None]: ...
|
|
195
240
|
|
|
196
|
-
|
|
197
|
-
|
|
241
|
+
api = GraphQLAPI(
|
|
242
|
+
query_type=Query,
|
|
243
|
+
mutation_type=Mutation,
|
|
244
|
+
subscription_type=Subscription
|
|
245
|
+
)
|
|
198
246
|
```
|
|
199
|
-
*Note: The mutation API is illustrative. The library's `GraphQLAPI` constructor may need to be extended to support mutations as shown.*
|
|
200
247
|
|
|
201
248
|
## Running Tests
|
|
202
249
|
|
|
@@ -12,6 +12,7 @@ A powerful and intuitive Python library for building GraphQL APIs, designed with
|
|
|
12
12
|
|
|
13
13
|
- **Decorator-Based Schema:** Define your GraphQL schema declaratively using simple and intuitive decorators.
|
|
14
14
|
- **Type Hinting:** Automatically converts Python type hints into GraphQL types.
|
|
15
|
+
- **Implicit Type Inference:** Automatically maps Pydantic models, dataclasses, and classes with fields - no explicit decorators needed.
|
|
15
16
|
- **Pydantic & Dataclass Support:** Seamlessly use Pydantic and Dataclass models as GraphQL types.
|
|
16
17
|
- **Asynchronous Execution:** Full support for `async` and `await` for high-performance, non-blocking resolvers.
|
|
17
18
|
- **Apollo Federation:** Built-in support for creating federated services.
|
|
@@ -84,6 +85,7 @@ class Book(BaseModel):
|
|
|
84
85
|
title: str
|
|
85
86
|
author: str
|
|
86
87
|
|
|
88
|
+
@api.type(is_root_type=True)
|
|
87
89
|
class BookAPI:
|
|
88
90
|
@api.field
|
|
89
91
|
def get_books(self) -> List[Book]:
|
|
@@ -92,7 +94,7 @@ class BookAPI:
|
|
|
92
94
|
Book(title="1984", author="George Orwell"),
|
|
93
95
|
]
|
|
94
96
|
|
|
95
|
-
api = GraphQLAPI(
|
|
97
|
+
api = GraphQLAPI()
|
|
96
98
|
|
|
97
99
|
graphql_query = """
|
|
98
100
|
query {
|
|
@@ -115,13 +117,14 @@ Define async resolvers for non-blocking I/O operations.
|
|
|
115
117
|
import asyncio
|
|
116
118
|
from graphql_api.api import GraphQLAPI
|
|
117
119
|
|
|
120
|
+
@api.type(is_root_type=True)
|
|
118
121
|
class AsyncAPI:
|
|
119
122
|
@api.field
|
|
120
123
|
async def fetch_data(self) -> str:
|
|
121
124
|
await asyncio.sleep(1)
|
|
122
125
|
return "Data fetched successfully!"
|
|
123
126
|
|
|
124
|
-
api = GraphQLAPI(
|
|
127
|
+
api = GraphQLAPI()
|
|
125
128
|
|
|
126
129
|
# To execute async queries, you'll need an async executor
|
|
127
130
|
# or to run it within an async context.
|
|
@@ -142,11 +145,11 @@ if __name__ == "__main__":
|
|
|
142
145
|
|
|
143
146
|
### Mutations with Dataclasses
|
|
144
147
|
|
|
145
|
-
Use dataclasses to define the structure of your
|
|
148
|
+
Use dataclasses to define the structure of your data, and mark fields as mutable to automatically separate them into the GraphQL Mutation type.
|
|
146
149
|
|
|
147
150
|
```python
|
|
148
151
|
from dataclasses import dataclass
|
|
149
|
-
from graphql_api.api import GraphQLAPI
|
|
152
|
+
from graphql_api.api import GraphQLAPI
|
|
150
153
|
|
|
151
154
|
@dataclass
|
|
152
155
|
class User:
|
|
@@ -156,22 +159,66 @@ class User:
|
|
|
156
159
|
# A simple in-memory database
|
|
157
160
|
db = {1: User(id=1, name="Alice")}
|
|
158
161
|
|
|
162
|
+
api = GraphQLAPI()
|
|
163
|
+
|
|
164
|
+
@api.type(is_root_type=True)
|
|
159
165
|
class Root:
|
|
160
|
-
@field
|
|
166
|
+
@api.field
|
|
161
167
|
def get_user(self, user_id: int) -> User:
|
|
162
168
|
return db.get(user_id)
|
|
163
169
|
|
|
164
|
-
|
|
165
|
-
@field
|
|
170
|
+
@api.field(mutable=True)
|
|
166
171
|
def add_user(self, user_id: int, name: str) -> User:
|
|
167
172
|
new_user = User(id=user_id, name=name)
|
|
168
173
|
db[user_id] = new_user
|
|
169
174
|
return new_user
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
GraphQL automatically separates queries and mutations - you don't need separate classes. Fields marked with `mutable=True` are placed in the Mutation type, while regular fields go in the Query type. Fields with `AsyncGenerator` return types are automatically detected as subscriptions. This automatic mapping means you can define all your operations in a single class and let `graphql-api` handle the schema organization for you.
|
|
178
|
+
|
|
179
|
+
## Two Approaches for Complex Schemas
|
|
180
|
+
|
|
181
|
+
`graphql-api` supports two approaches for organizing your GraphQL schema:
|
|
182
|
+
|
|
183
|
+
### Single Root Type (Recommended)
|
|
184
|
+
```python
|
|
185
|
+
@api.type(is_root_type=True)
|
|
186
|
+
class Root:
|
|
187
|
+
@api.field
|
|
188
|
+
def query_field(self) -> str: ...
|
|
189
|
+
|
|
190
|
+
@api.field(mutable=True)
|
|
191
|
+
def mutation_field(self) -> str: ...
|
|
192
|
+
|
|
193
|
+
@api.field
|
|
194
|
+
async def subscription_field(self) -> AsyncGenerator[str, None]: ...
|
|
195
|
+
|
|
196
|
+
api = GraphQLAPI(root_type=Root)
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Explicit Types
|
|
200
|
+
```python
|
|
201
|
+
@api.type
|
|
202
|
+
class Query:
|
|
203
|
+
@api.field
|
|
204
|
+
def query_field(self) -> str: ...
|
|
205
|
+
|
|
206
|
+
@api.type
|
|
207
|
+
class Mutation:
|
|
208
|
+
@api.field
|
|
209
|
+
def mutation_field(self) -> str: ...
|
|
210
|
+
|
|
211
|
+
@api.type
|
|
212
|
+
class Subscription:
|
|
213
|
+
@api.field
|
|
214
|
+
async def subscription_field(self) -> AsyncGenerator[str, None]: ...
|
|
170
215
|
|
|
171
|
-
|
|
172
|
-
|
|
216
|
+
api = GraphQLAPI(
|
|
217
|
+
query_type=Query,
|
|
218
|
+
mutation_type=Mutation,
|
|
219
|
+
subscription_type=Subscription
|
|
220
|
+
)
|
|
173
221
|
```
|
|
174
|
-
*Note: The mutation API is illustrative. The library's `GraphQLAPI` constructor may need to be extended to support mutations as shown.*
|
|
175
222
|
|
|
176
223
|
## Running Tests
|
|
177
224
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.4.20
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# GraphQL API Documentation
|
|
2
|
+
|
|
3
|
+
This directory contains the documentation for the GraphQL API library, built with Jekyll and deployed to GitHub Pages.
|
|
4
|
+
|
|
5
|
+
## Local Development
|
|
6
|
+
|
|
7
|
+
### Prerequisites
|
|
8
|
+
|
|
9
|
+
- Ruby 2.7 or newer
|
|
10
|
+
- Bundler gem
|
|
11
|
+
|
|
12
|
+
### Setup
|
|
13
|
+
|
|
14
|
+
1. Install dependencies:
|
|
15
|
+
```bash
|
|
16
|
+
cd docs
|
|
17
|
+
bundle install
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
2. Serve the site locally:
|
|
21
|
+
```bash
|
|
22
|
+
bundle exec jekyll serve
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
3. Open http://localhost:4000 in your browser
|
|
26
|
+
|
|
27
|
+
### Project Structure
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
docs/
|
|
31
|
+
├── _config.yml # Jekyll configuration
|
|
32
|
+
├── _layouts/ # Page layouts
|
|
33
|
+
│ └── default.html # Main layout template
|
|
34
|
+
├── assets/ # CSS, JS, and other assets
|
|
35
|
+
│ └── css/
|
|
36
|
+
│ └── style.scss # Main stylesheet
|
|
37
|
+
├── index.md # Homepage
|
|
38
|
+
├── getting-started.md # Getting started guide
|
|
39
|
+
├── examples.md # Examples and tutorials
|
|
40
|
+
├── api-reference.md # Complete API reference
|
|
41
|
+
├── contributing.md # Contributing guidelines
|
|
42
|
+
├── Gemfile # Ruby dependencies
|
|
43
|
+
└── README.md # This file
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Adding Content
|
|
47
|
+
|
|
48
|
+
### New Pages
|
|
49
|
+
|
|
50
|
+
1. Create a new Markdown file in the docs directory
|
|
51
|
+
2. Add front matter at the top:
|
|
52
|
+
```yaml
|
|
53
|
+
---
|
|
54
|
+
layout: default
|
|
55
|
+
title: "Page Title"
|
|
56
|
+
description: "Page description"
|
|
57
|
+
---
|
|
58
|
+
```
|
|
59
|
+
3. Add the page to navigation in `_config.yml` if needed
|
|
60
|
+
|
|
61
|
+
### Updating Existing Content
|
|
62
|
+
|
|
63
|
+
Simply edit the corresponding Markdown files. The site will rebuild automatically when changes are pushed to the main branch.
|
|
64
|
+
|
|
65
|
+
## Deployment
|
|
66
|
+
|
|
67
|
+
The documentation is automatically deployed to GitHub Pages via GitHub Actions when changes are pushed to the main branch. The workflow is defined in `.github/workflows/pages.yml`.
|
|
68
|
+
|
|
69
|
+
## Customization
|
|
70
|
+
|
|
71
|
+
### Styling
|
|
72
|
+
|
|
73
|
+
The main stylesheet is in `assets/css/style.scss`. It imports the base theme and adds custom styling for the documentation.
|
|
74
|
+
|
|
75
|
+
### Layout
|
|
76
|
+
|
|
77
|
+
The main layout template is in `_layouts/default.html`. It includes the header, navigation, content area, and footer.
|
|
78
|
+
|
|
79
|
+
### Configuration
|
|
80
|
+
|
|
81
|
+
Site configuration is in `_config.yml`. This includes site metadata, navigation, and Jekyll settings.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "GraphQL API for Python"
|
|
3
|
+
type: docs
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
> **A powerful and intuitive Python library for building GraphQL APIs with a code-first, decorator-based approach.**
|
|
7
|
+
|
|
8
|
+
# GraphQL API for Python
|
|
9
|
+
|
|
10
|
+
[](https://badge.fury.io/py/graphql-api)
|
|
11
|
+
[](https://pypi.org/project/graphql-api/)
|
|
12
|
+
[](https://opensource.org/licenses/MIT)
|
|
13
|
+
|
|
14
|
+
## Why GraphQL API?
|
|
15
|
+
|
|
16
|
+
`graphql-api` simplifies schema definition by leveraging Python's type hints, dataclasses, and Pydantic models, allowing you to build robust and maintainable GraphQL services with minimal boilerplate.
|
|
17
|
+
|
|
18
|
+
## Key Features
|
|
19
|
+
|
|
20
|
+
| Feature | Description |
|
|
21
|
+
|---------|-------------|
|
|
22
|
+
| 🎯 **Code-First Approach** | Define your GraphQL schema using Python decorators and type hints. No SDL required. |
|
|
23
|
+
| ⚡ **Type Safety** | Automatic type conversion from Python types to GraphQL types with full type checking support. |
|
|
24
|
+
| 🔄 **Async Support** | Built-in support for async/await patterns and real-time subscriptions. |
|
|
25
|
+
| 🧩 **Pydantic Integration** | Seamlessly use Pydantic models and dataclasses as GraphQL types. |
|
|
26
|
+
| 🌐 **Federation Ready** | Built-in Apollo Federation support for microservice architectures. |
|
|
27
|
+
| 🎛️ **Flexible Schema** | Choose between unified root types or explicit query/mutation/subscription separation. |
|
|
28
|
+
|
|
29
|
+
## Quick Start
|
|
30
|
+
|
|
31
|
+
Get up and running in minutes:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install graphql-api
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
from graphql_api.api import GraphQLAPI
|
|
39
|
+
|
|
40
|
+
# Initialize the API
|
|
41
|
+
api = GraphQLAPI()
|
|
42
|
+
|
|
43
|
+
# Define your schema with decorators
|
|
44
|
+
@api.type(is_root_type=True)
|
|
45
|
+
class Query:
|
|
46
|
+
@api.field
|
|
47
|
+
def hello(self, name: str = "World") -> str:
|
|
48
|
+
return f"Hello, {name}!"
|
|
49
|
+
|
|
50
|
+
# Execute queries
|
|
51
|
+
result = api.execute('{ hello(name: "Developer") }')
|
|
52
|
+
print(result.data) # {'hello': 'Hello, Developer!'}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Key Features
|
|
56
|
+
|
|
57
|
+
- **Decorator-Based Schema:** Define your GraphQL schema declaratively using simple and intuitive decorators
|
|
58
|
+
- **Type Hinting:** Automatically converts Python type hints into GraphQL types
|
|
59
|
+
- **Implicit Type Inference:** Automatically maps Pydantic models, dataclasses, and classes with fields
|
|
60
|
+
- **Pydantic & Dataclass Support:** Seamlessly use Pydantic and Dataclass models as GraphQL types
|
|
61
|
+
- **Asynchronous Execution:** Full support for `async` and `await` for high-performance, non-blocking resolvers
|
|
62
|
+
- **Apollo Federation:** Built-in support for creating federated services
|
|
63
|
+
- **Subscriptions:** Implement real-time functionality with GraphQL subscriptions
|
|
64
|
+
- **Middleware:** Add custom logic to your resolvers with a flexible middleware system
|
|
65
|
+
- **Relay Support:** Includes helpers for building Relay-compliant schemas
|
|
66
|
+
|
|
67
|
+
## What's Next?
|
|
68
|
+
|
|
69
|
+
- 📚 **[Getting Started](docs/getting-started/)** - Learn the basics with our comprehensive guide
|
|
70
|
+
- 💡 **[Examples](docs/examples/)** - Explore practical examples and tutorials for real-world scenarios
|
|
71
|
+
- 📖 **[API Reference](docs/api-reference/)** - Check out the complete API documentation
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Documentation"
|
|
3
|
+
weight: 1
|
|
4
|
+
bookCollapseSection: false
|
|
5
|
+
bookFlatSection: true
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
> **Complete documentation for GraphQL API, from basic concepts to advanced features.**
|
|
9
|
+
|
|
10
|
+
Welcome to the GraphQL API documentation! This section contains everything you need to know to build powerful GraphQL APIs with Python.
|
|
11
|
+
|
|
12
|
+
## Getting Started
|
|
13
|
+
|
|
14
|
+
New to GraphQL API? Start here:
|
|
15
|
+
|
|
16
|
+
- **[Getting Started](getting-started/)** - Installation and your first API
|
|
17
|
+
|
|
18
|
+
## Guides
|
|
19
|
+
|
|
20
|
+
Step-by-step guides for common tasks:
|
|
21
|
+
|
|
22
|
+
- **[Examples & Tutorials](examples/)** - Practical examples and tutorials
|
|
23
|
+
- **[Schema Definition](defining-schemas/)** - How to define types and fields
|
|
24
|
+
- **[Pydantic & Dataclasses](pydantic-and-dataclasses/)** - Working with data models
|
|
25
|
+
- **[Async & Subscriptions](async-and-subscriptions/)** - Real-time functionality
|
|
26
|
+
|
|
27
|
+
## Advanced Topics
|
|
28
|
+
|
|
29
|
+
For experienced users:
|
|
30
|
+
|
|
31
|
+
- **[Apollo Federation](federation/)** - Building distributed graphs
|
|
32
|
+
- **[Advanced Features](advanced/)** - Middleware, directives, and more
|
|
33
|
+
|
|
34
|
+
## Reference
|
|
35
|
+
|
|
36
|
+
Complete API documentation:
|
|
37
|
+
|
|
38
|
+
- **[API Reference](api-reference/)** - Classes, methods, and functions
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Advanced Topics"
|
|
3
|
+
linkTitle: "Advanced"
|
|
4
|
+
weight: 7
|
|
5
|
+
description: >
|
|
6
|
+
Explore advanced features like middleware, directives, and Relay support
|
|
7
|
+
---
|
|
8
|
+
|
|
1
9
|
# Advanced Topics
|
|
2
10
|
|
|
3
11
|
This section covers some of the more advanced features of `graphql-api`, including middleware, error handling, resolver context, directives, and Relay support.
|
|
@@ -55,12 +63,14 @@ class UserNotFoundError(GraphQLError):
|
|
|
55
63
|
)
|
|
56
64
|
|
|
57
65
|
# In a resolver, you can raise this exception
|
|
58
|
-
@api.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
66
|
+
@api.type(is_root_type=True)
|
|
67
|
+
class Query:
|
|
68
|
+
@api.field
|
|
69
|
+
def get_user_by_id(self, user_id: int) -> User:
|
|
70
|
+
user = find_user_in_db(user_id)
|
|
71
|
+
if not user:
|
|
72
|
+
raise UserNotFoundError(user_id)
|
|
73
|
+
return user
|
|
64
74
|
```
|
|
65
75
|
|
|
66
76
|
When this resolver is executed with an invalid ID, the client will receive a structured error in the response:
|
|
@@ -109,15 +119,17 @@ result = api.execute(
|
|
|
109
119
|
The context is available via the `info` argument (which is of type `GraphQLResolveInfo`) that is passed to every resolver.
|
|
110
120
|
|
|
111
121
|
```python
|
|
112
|
-
@api.
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
122
|
+
@api.type(is_root_type=True)
|
|
123
|
+
class Query:
|
|
124
|
+
@api.field
|
|
125
|
+
def get_my_profile(self, info) -> User:
|
|
126
|
+
# Access the context from the `info` object.
|
|
127
|
+
current_user = info.context.get("current_user")
|
|
116
128
|
|
|
117
|
-
|
|
118
|
-
|
|
129
|
+
if not current_user:
|
|
130
|
+
raise PermissionError("You must be logged in to view your profile.")
|
|
119
131
|
|
|
120
|
-
|
|
132
|
+
return current_user
|
|
121
133
|
```
|
|
122
134
|
|
|
123
135
|
Using the context is the recommended way to provide resolvers with request-scoped data, keeping them decoupled from the transport layer (e.g., HTTP).
|