-
Notifications
You must be signed in to change notification settings - Fork 184
Add gql compiler #185
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Add gql compiler #185
Changes from 1 commit
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
Compiling queries to strongly typed classes | ||
=========================================== | ||
|
||
It is possible to create strongly typed classes for querying graphql based on graphql schema. | ||
It is similar to how other libraries generate code for API schema types like gRPC and Thrift. | ||
|
||
The compliation is very helpful for building GraphQL based SDK in a fast and safe way as it helps you guarantee the following: | ||
|
||
1. GraphQL queries are valid - Queries are now validated in compile time and not just in runtime | ||
2. Python usage of query classes is valid - Using static typing (like mypy - http://mypy-lang.org/) | ||
3. Changes over time in graphql schema doesn't break existing SDKs - You can use verify flag of the compiler and integrate it in your CI/CD | ||
|
||
Usage | ||
----- | ||
|
||
After installation you should compile your queries with running | ||
|
||
.. code-block:: bash | ||
|
||
gql-compiler {schema_library} {graphql_library} | ||
|
||
* ``schema_library`` is where the folder where the graphql schema (or schemas) are located | ||
* ``graphql_library`` is where you locate then queries that you'd like to compile (``Query``, ``Mutation`` and ``Subscription`` are supported) | ||
|
||
Example: | ||
|
||
In the ``graphql_library`` create the file ``query.graphql``: | ||
|
||
.. code-block:: | ||
|
||
query DogQuery($id: String!) { | ||
dog(id: $id) { | ||
id | ||
name | ||
breed | ||
age | ||
} | ||
} | ||
|
||
After compilation it will create the file ``query.py`` in the same | ||
folder: | ||
|
||
.. code-block:: python | ||
|
||
#!/usr/bin/env python3 | ||
# @generated AUTOGENERATED file. Do not Change! | ||
|
||
from dataclasses import dataclass, field | ||
from gql_client.runtime.variables import encode_variables | ||
from gql import gql, Client | ||
from gql.transport.exceptions import TransportQueryError | ||
from functools import partial | ||
from numbers import Number | ||
from typing import Any, AsyncGenerator, Dict, List, Generator, Optional | ||
from time import perf_counter | ||
from dataclasses_json import DataClassJsonMixin, config | ||
|
||
from gql_client.runtime.enum_utils import enum_field_metadata | ||
from .enum.dog_breed import DogBreed | ||
|
||
|
||
# fmt: off | ||
QUERY: List[str] = [""" | ||
query DogQuery($id: String!) { | ||
dog(id: $id) { | ||
id | ||
name | ||
breed | ||
age | ||
} | ||
} | ||
""" | ||
] | ||
|
||
|
||
class DogQuery: | ||
@dataclass(frozen=True) | ||
class DogQueryData(DataClassJsonMixin): | ||
@dataclass(frozen=True) | ||
class Dog(DataClassJsonMixin): | ||
id: str | ||
name: Optional[str] | ||
breed: Optional[DogBreed] = field(metadata=enum_field_metadata(DogBreed)) | ||
age: Optional[int] | ||
|
||
dog: Optional[Dog] | ||
|
||
# fmt: off | ||
@classmethod | ||
def execute(cls, client: Client, id: str) -> Optional[DogQueryData.Dog]: | ||
variables: Dict[str, Any] = {"id": id} | ||
new_variables = encode_variables(variables) | ||
response_text = client.execute( | ||
gql("".join(set(QUERY))), variable_values=new_variables | ||
) | ||
res = cls.DogQueryData.from_dict(response_text) | ||
return res.dog | ||
|
||
# fmt: off | ||
@classmethod | ||
async def execute_async(cls, client: Client, id: str) -> Optional[DogQueryData.Dog]: | ||
variables: Dict[str, Any] = {"id": id} | ||
new_variables = encode_variables(variables) | ||
response_text = await client.execute_async( | ||
gql("".join(set(QUERY))), variable_values=new_variables | ||
) | ||
res = cls.DogQueryData.from_dict(response_text) | ||
return res.dog | ||
|
||
|
||
An example for using the generated class: | ||
|
||
.. code-block:: python | ||
|
||
from gql import Client | ||
from gql.transport.aiohttp import AIOHTTPTransport | ||
from gql_client.runtime.graphql_client import GraphqlClient | ||
from query import DogQuery | ||
|
||
transport = AIOHTTPTransport(url="http://.../graph/query") | ||
client = Client(transport=transport, fetch_schema_from_transport=True) | ||
result = DogQuery.execute(client, id="1000") | ||
|
||
|
||
Custom Scalars | ||
-------------- | ||
|
||
If your graphql schema contains custom scalars you should create python | ||
configuration file with the definitions of the custom scalars and use in | ||
the compilation command with ``--config_path`` option. In the | ||
configuration file you should have ``custom_scalars`` variable of type | ||
``Dict[str, CustomScalar]``. Simple example: | ||
|
||
.. code-block:: python | ||
|
||
from gql_client.compiler.renderer_dataclasses import CustomScalar | ||
from typing import Dict | ||
|
||
custom_scalars: Dict[str, CustomScalar] = { | ||
"Cursor": CustomScalar( | ||
name="Cursor", | ||
type=str, | ||
), | ||
} | ||
|
||
|
||
CustomScalar also has ``encoder``, ``decoder`` and ``mm_field`` fields that can be used when the custom scalar is defined with complex type that requires encoding-decoding from the string that is being sent in the graphql response. | ||
|
||
More features | ||
------------- | ||
|
||
- Create fragments query files and share them between other query files | ||
- Compiler has an option to only verify compiled query files without | ||
re-genrating them (``--verify`` option) | ||
naormatania marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- Compiler can be configured to raise an error if queries use | ||
deprecated fields (``--allow-deprecated`` option) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,3 +8,4 @@ Advanced | |
logging | ||
local_schema | ||
dsl_module | ||
compiler |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
"""The :mod:`compiler` package includes compiler for compiling graphql query files to | ||
strongly typed classes. | ||
More details can be found in | ||
[Documentation](https://gql.readthedocs.io/en/latest/advanced/compiler.html) | ||
""" |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.