graphql-api 1.4.18__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.20/.github/workflows/python-package.yml +78 -0
- graphql_api-1.4.20/.gitignore +23 -0
- graphql_api-1.4.20/.vscode/settings.json +7 -0
- {graphql_api-1.4.18/graphql_api.egg-info → graphql_api-1.4.20}/PKG-INFO +68 -38
- {graphql_api-1.4.18 → 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.20/docs/content/docs/advanced.md +202 -0
- graphql_api-1.4.20/docs/content/docs/api-reference.md +551 -0
- graphql_api-1.4.20/docs/content/docs/async-and-subscriptions.md +161 -0
- graphql_api-1.4.20/docs/content/docs/contributing.md +442 -0
- graphql_api-1.4.20/docs/content/docs/defining-schemas.md +279 -0
- graphql_api-1.4.20/docs/content/docs/examples.md +528 -0
- graphql_api-1.4.20/docs/content/docs/federation.md +147 -0
- graphql_api-1.4.20/docs/content/docs/getting-started.md +140 -0
- graphql_api-1.4.20/docs/content/docs/pydantic-and-dataclasses.md +184 -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.18 → graphql_api-1.4.20}/graphql_api/api.py +157 -23
- {graphql_api-1.4.18 → graphql_api-1.4.20}/graphql_api/dataclass_mapping.py +8 -4
- {graphql_api-1.4.18 → graphql_api-1.4.20}/graphql_api/directives.py +6 -3
- {graphql_api-1.4.18 → graphql_api-1.4.20}/graphql_api/executor.py +6 -3
- {graphql_api-1.4.18 → graphql_api-1.4.20}/graphql_api/federation/directives.py +4 -2
- {graphql_api-1.4.18 → graphql_api-1.4.20}/graphql_api/federation/federation.py +4 -2
- {graphql_api-1.4.18 → graphql_api-1.4.20}/graphql_api/mapper.py +68 -20
- {graphql_api-1.4.18 → graphql_api-1.4.20}/graphql_api/pydantic.py +4 -2
- {graphql_api-1.4.18 → graphql_api-1.4.20}/graphql_api/reduce.py +28 -14
- {graphql_api-1.4.18 → graphql_api-1.4.20}/graphql_api/remote.py +18 -9
- {graphql_api-1.4.18 → graphql_api-1.4.20}/graphql_api/schema.py +11 -5
- {graphql_api-1.4.18 → graphql_api-1.4.20}/graphql_api/types.py +4 -2
- {graphql_api-1.4.18 → graphql_api-1.4.20}/graphql_api/utils.py +4 -2
- {graphql_api-1.4.18 → graphql_api-1.4.20/graphql_api.egg-info}/PKG-INFO +68 -38
- {graphql_api-1.4.18 → graphql_api-1.4.20}/graphql_api.egg-info/SOURCES.txt +23 -4
- graphql_api-1.4.20/graphql_api.egg-info/requires.txt +6 -0
- {graphql_api-1.4.18 → graphql_api-1.4.20}/graphql_api.egg-info/top_level.txt +0 -1
- graphql_api-1.4.20/pyproject.toml +80 -0
- graphql_api-1.4.20/setup.cfg +4 -0
- {graphql_api-1.4.18 → graphql_api-1.4.20}/tests/test_async.py +2 -1
- {graphql_api-1.4.18 → graphql_api-1.4.20}/tests/test_calculator.py +5 -5
- {graphql_api-1.4.18 → graphql_api-1.4.20}/tests/test_custom_types.py +17 -15
- {graphql_api-1.4.18 → graphql_api-1.4.20}/tests/test_dataclass.py +66 -33
- {graphql_api-1.4.18 → graphql_api-1.4.20}/tests/test_directives.py +26 -18
- {graphql_api-1.4.18 → graphql_api-1.4.20}/tests/test_docstrings.py +36 -24
- {graphql_api-1.4.18 → graphql_api-1.4.20}/tests/test_error.py +6 -6
- {graphql_api-1.4.18 → graphql_api-1.4.20}/tests/test_federation.py +4 -3
- graphql_api-1.4.20/tests/test_federation_example.graphql +83 -0
- {graphql_api-1.4.18 → graphql_api-1.4.20}/tests/test_federation_example.py +8 -8
- {graphql_api-1.4.18 → graphql_api-1.4.20}/tests/test_filtering.py +109 -71
- {graphql_api-1.4.18 → graphql_api-1.4.20}/tests/test_graphql.py +82 -72
- {graphql_api-1.4.18 → graphql_api-1.4.20}/tests/test_middleware.py +3 -3
- {graphql_api-1.4.18 → graphql_api-1.4.20}/tests/test_pydantic.py +44 -33
- {graphql_api-1.4.18 → graphql_api-1.4.20}/tests/test_relay.py +1 -1
- {graphql_api-1.4.18 → graphql_api-1.4.20}/tests/test_remote.py +73 -44
- {graphql_api-1.4.18 → graphql_api-1.4.20}/tests/test_schema.py +9 -8
- {graphql_api-1.4.18 → graphql_api-1.4.20}/tests/test_subscriptions.py +16 -13
- graphql_api-1.4.20/tests/test_unified_vs_explicit_schema.py +241 -0
- graphql_api-1.4.20/uv.lock +948 -0
- graphql_api-1.4.18/MANIFEST.in +0 -3
- graphql_api-1.4.18/VERSION +0 -1
- graphql_api-1.4.18/graphql_api.egg-info/requires.txt +0 -12
- graphql_api-1.4.18/setup.cfg +0 -15
- graphql_api-1.4.18/setup.py +0 -46
- {graphql_api-1.4.18 → graphql_api-1.4.20}/LICENSE +0 -0
- {graphql_api-1.4.18 → graphql_api-1.4.20}/graphql_api/__init__.py +0 -0
- {graphql_api-1.4.18 → graphql_api-1.4.20}/graphql_api/context.py +0 -0
- {graphql_api-1.4.18 → graphql_api-1.4.20}/graphql_api/decorators.py +0 -0
- {graphql_api-1.4.18 → graphql_api-1.4.20}/graphql_api/error.py +0 -0
- {graphql_api-1.4.18 → graphql_api-1.4.20}/graphql_api/exception.py +0 -0
- {graphql_api-1.4.18 → graphql_api-1.4.20}/graphql_api/federation/__init__.py +0 -0
- {graphql_api-1.4.18 → graphql_api-1.4.20}/graphql_api/federation/types.py +0 -0
- {graphql_api-1.4.18 → graphql_api-1.4.20}/graphql_api/middleware.py +0 -0
- {graphql_api-1.4.18 → graphql_api-1.4.20}/graphql_api/relay.py +0 -0
- {graphql_api-1.4.18 → graphql_api-1.4.20}/graphql_api.egg-info/dependency_links.txt +0 -0
- {graphql_api-1.4.18 → graphql_api-1.4.20}/tests/__init__.py +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
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
name: Python Package CI/CD
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main # Or your default branch
|
|
7
|
+
tags:
|
|
8
|
+
- '*.*.*' # For publishing to PyPI
|
|
9
|
+
pull_request:
|
|
10
|
+
branches:
|
|
11
|
+
- main # Or your default branch
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
build_and_test:
|
|
15
|
+
name: Build and Test (Python ${{ matrix.python-version }})
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
strategy:
|
|
18
|
+
fail-fast: false
|
|
19
|
+
matrix:
|
|
20
|
+
python-version: ["3.11", "3.12"] # graphql-api requires Python 3.11+
|
|
21
|
+
|
|
22
|
+
steps:
|
|
23
|
+
- name: Checkout repository
|
|
24
|
+
uses: actions/checkout@v4
|
|
25
|
+
|
|
26
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
27
|
+
uses: actions/setup-python@v5
|
|
28
|
+
with:
|
|
29
|
+
python-version: ${{ matrix.python-version }}
|
|
30
|
+
|
|
31
|
+
- name: Install UV
|
|
32
|
+
uses: astral-sh/setup-uv@v3
|
|
33
|
+
|
|
34
|
+
- name: Install dependencies
|
|
35
|
+
run: uv sync --dev
|
|
36
|
+
|
|
37
|
+
- name: Lint with Flake8
|
|
38
|
+
run: uv run flake8 graphql_api tests
|
|
39
|
+
|
|
40
|
+
- name: Test with Pytest
|
|
41
|
+
run: uv run pytest
|
|
42
|
+
|
|
43
|
+
publish:
|
|
44
|
+
name: Publish to PyPI
|
|
45
|
+
needs: build_and_test # Ensure tests pass before publishing
|
|
46
|
+
runs-on: ubuntu-latest
|
|
47
|
+
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
|
48
|
+
permissions:
|
|
49
|
+
id-token: write
|
|
50
|
+
|
|
51
|
+
steps:
|
|
52
|
+
- name: Validate tag format (e.g., 1.0.0)
|
|
53
|
+
run: |
|
|
54
|
+
TAG_NAME="${{ github.ref_name }}"
|
|
55
|
+
if ! [[ "$TAG_NAME" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
56
|
+
echo "Error: Tag '$TAG_NAME' is not in the required X.Y.Z numeric format (e.g., 1.0.0)."
|
|
57
|
+
exit 1
|
|
58
|
+
fi
|
|
59
|
+
echo "Tag '$TAG_NAME' is valid."
|
|
60
|
+
shell: bash
|
|
61
|
+
|
|
62
|
+
- name: Checkout repository
|
|
63
|
+
uses: actions/checkout@v4
|
|
64
|
+
|
|
65
|
+
- name: Set up Python
|
|
66
|
+
uses: actions/setup-python@v5
|
|
67
|
+
with:
|
|
68
|
+
python-version: '3.12' # Use compatible Python version
|
|
69
|
+
|
|
70
|
+
- name: Install UV
|
|
71
|
+
uses: astral-sh/setup-uv@v3
|
|
72
|
+
|
|
73
|
+
- name: Update VERSION file
|
|
74
|
+
run: echo "${{ github.ref_name }}" > VERSION
|
|
75
|
+
shell: bash
|
|
76
|
+
|
|
77
|
+
- name: Build and publish package to PyPI
|
|
78
|
+
run: uv build && uv publish
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
.idea
|
|
2
|
+
.DS_Store
|
|
3
|
+
.coverage
|
|
4
|
+
.pytest_cache
|
|
5
|
+
|
|
6
|
+
# Virtual environments
|
|
7
|
+
.venv/
|
|
8
|
+
env/
|
|
9
|
+
venv/
|
|
10
|
+
|
|
11
|
+
# Build artifacts
|
|
12
|
+
build/
|
|
13
|
+
dist/
|
|
14
|
+
*.egg-info/
|
|
15
|
+
|
|
16
|
+
# Testing
|
|
17
|
+
tests/logs/
|
|
18
|
+
tests/htmlcov/
|
|
19
|
+
htmlcov/
|
|
20
|
+
|
|
21
|
+
# Python
|
|
22
|
+
*.pyc
|
|
23
|
+
__pycache__/
|
|
@@ -1,44 +1,27 @@
|
|
|
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
|
-
|
|
6
|
-
Download-URL: https://gitlab.com/parob/graphql/-/archive/v1.4.18/graphql_api-v1.4.18.tar.gz
|
|
7
|
-
Author: Robert Parker
|
|
8
|
-
Author-email: rob@parob.com
|
|
5
|
+
Author-email: Robert Parker <rob@parob.com>
|
|
9
6
|
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://gitlab.com/parob/graphql-api
|
|
8
|
+
Project-URL: Repository, https://gitlab.com/parob/graphql-api
|
|
10
9
|
Keywords: GraphQL,GraphQL-API,GraphQLAPI,Server
|
|
11
10
|
Classifier: Development Status :: 3 - Alpha
|
|
12
11
|
Classifier: Intended Audience :: Developers
|
|
13
12
|
Classifier: Programming Language :: Python :: 3
|
|
14
13
|
Classifier: License :: OSI Approved :: MIT License
|
|
15
14
|
Classifier: Operating System :: OS Independent
|
|
15
|
+
Requires-Python: <3.13,>=3.11
|
|
16
16
|
Description-Content-Type: text/markdown
|
|
17
17
|
License-File: LICENSE
|
|
18
|
-
Requires-Dist: graphql-core
|
|
19
|
-
Requires-Dist: requests
|
|
20
|
-
Requires-Dist: typing-inspect
|
|
21
|
-
Requires-Dist: aiohttp
|
|
22
|
-
Requires-Dist: docstring-parser
|
|
23
|
-
Requires-Dist: pydantic
|
|
24
|
-
Provides-Extra: dev
|
|
25
|
-
Requires-Dist: pytest~=5.4; extra == "dev"
|
|
26
|
-
Requires-Dist: pytest-cov~=2.10; extra == "dev"
|
|
27
|
-
Requires-Dist: coverage~=5.2; extra == "dev"
|
|
28
|
-
Requires-Dist: faker~=4.1; extra == "dev"
|
|
29
|
-
Dynamic: author
|
|
30
|
-
Dynamic: author-email
|
|
31
|
-
Dynamic: classifier
|
|
32
|
-
Dynamic: description
|
|
33
|
-
Dynamic: description-content-type
|
|
34
|
-
Dynamic: download-url
|
|
35
|
-
Dynamic: home-page
|
|
36
|
-
Dynamic: keywords
|
|
37
|
-
Dynamic: license
|
|
18
|
+
Requires-Dist: graphql-core
|
|
19
|
+
Requires-Dist: requests
|
|
20
|
+
Requires-Dist: typing-inspect
|
|
21
|
+
Requires-Dist: aiohttp
|
|
22
|
+
Requires-Dist: docstring-parser
|
|
23
|
+
Requires-Dist: pydantic
|
|
38
24
|
Dynamic: license-file
|
|
39
|
-
Dynamic: provides-extra
|
|
40
|
-
Dynamic: requires-dist
|
|
41
|
-
Dynamic: summary
|
|
42
25
|
|
|
43
26
|
# GraphQL API for Python
|
|
44
27
|
|
|
@@ -54,6 +37,7 @@ A powerful and intuitive Python library for building GraphQL APIs, designed with
|
|
|
54
37
|
|
|
55
38
|
- **Decorator-Based Schema:** Define your GraphQL schema declaratively using simple and intuitive decorators.
|
|
56
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.
|
|
57
41
|
- **Pydantic & Dataclass Support:** Seamlessly use Pydantic and Dataclass models as GraphQL types.
|
|
58
42
|
- **Asynchronous Execution:** Full support for `async` and `await` for high-performance, non-blocking resolvers.
|
|
59
43
|
- **Apollo Federation:** Built-in support for creating federated services.
|
|
@@ -126,6 +110,7 @@ class Book(BaseModel):
|
|
|
126
110
|
title: str
|
|
127
111
|
author: str
|
|
128
112
|
|
|
113
|
+
@api.type(is_root_type=True)
|
|
129
114
|
class BookAPI:
|
|
130
115
|
@api.field
|
|
131
116
|
def get_books(self) -> List[Book]:
|
|
@@ -134,7 +119,7 @@ class BookAPI:
|
|
|
134
119
|
Book(title="1984", author="George Orwell"),
|
|
135
120
|
]
|
|
136
121
|
|
|
137
|
-
api = GraphQLAPI(
|
|
122
|
+
api = GraphQLAPI()
|
|
138
123
|
|
|
139
124
|
graphql_query = """
|
|
140
125
|
query {
|
|
@@ -157,13 +142,14 @@ Define async resolvers for non-blocking I/O operations.
|
|
|
157
142
|
import asyncio
|
|
158
143
|
from graphql_api.api import GraphQLAPI
|
|
159
144
|
|
|
145
|
+
@api.type(is_root_type=True)
|
|
160
146
|
class AsyncAPI:
|
|
161
147
|
@api.field
|
|
162
148
|
async def fetch_data(self) -> str:
|
|
163
149
|
await asyncio.sleep(1)
|
|
164
150
|
return "Data fetched successfully!"
|
|
165
151
|
|
|
166
|
-
api = GraphQLAPI(
|
|
152
|
+
api = GraphQLAPI()
|
|
167
153
|
|
|
168
154
|
# To execute async queries, you'll need an async executor
|
|
169
155
|
# or to run it within an async context.
|
|
@@ -184,11 +170,11 @@ if __name__ == "__main__":
|
|
|
184
170
|
|
|
185
171
|
### Mutations with Dataclasses
|
|
186
172
|
|
|
187
|
-
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.
|
|
188
174
|
|
|
189
175
|
```python
|
|
190
176
|
from dataclasses import dataclass
|
|
191
|
-
from graphql_api.api import GraphQLAPI
|
|
177
|
+
from graphql_api.api import GraphQLAPI
|
|
192
178
|
|
|
193
179
|
@dataclass
|
|
194
180
|
class User:
|
|
@@ -198,22 +184,66 @@ class User:
|
|
|
198
184
|
# A simple in-memory database
|
|
199
185
|
db = {1: User(id=1, name="Alice")}
|
|
200
186
|
|
|
187
|
+
api = GraphQLAPI()
|
|
188
|
+
|
|
189
|
+
@api.type(is_root_type=True)
|
|
201
190
|
class Root:
|
|
202
|
-
@field
|
|
191
|
+
@api.field
|
|
203
192
|
def get_user(self, user_id: int) -> User:
|
|
204
193
|
return db.get(user_id)
|
|
205
194
|
|
|
206
|
-
|
|
207
|
-
@field
|
|
195
|
+
@api.field(mutable=True)
|
|
208
196
|
def add_user(self, user_id: int, name: str) -> User:
|
|
209
197
|
new_user = User(id=user_id, name=name)
|
|
210
198
|
db[user_id] = new_user
|
|
211
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]: ...
|
|
212
240
|
|
|
213
|
-
|
|
214
|
-
|
|
241
|
+
api = GraphQLAPI(
|
|
242
|
+
query_type=Query,
|
|
243
|
+
mutation_type=Mutation,
|
|
244
|
+
subscription_type=Subscription
|
|
245
|
+
)
|
|
215
246
|
```
|
|
216
|
-
*Note: The mutation API is illustrative. The library's `GraphQLAPI` constructor may need to be extended to support mutations as shown.*
|
|
217
247
|
|
|
218
248
|
## Running Tests
|
|
219
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
|