Skip to main content

Client library for making graphql calls.

Project description

codecov

Documentation Status

A pythonic interface for making requests to a GraphQL server using pydantic V2 BaseModels to spare you from string manipulation.

Features

  • Use pydantic v2 BaseModels to specify graphql parameters and responses

  • As of gqlclient v2, standard library dataclasses are no longer supported

  • As of gqlclient v2, pydantic dataclasses are no longer supported

  • Create and execute GraphQL Queries based upon typed models

  • Create and execute GraphQL Mutations based upon typed models

  • Async support

Installation

pip install gqlclient

with asyncio support

pip install gqlclient[async]

for developers

pip install gqlclient[test]
pip install pre-commit
pre-commit install

Examples

Query

# limited to pydantic V2
from pydantic import BaseModel

from gqlclient import GraphQLClient
from gqlclient.request_wrap import wrap_request
from gqlclient.response_encoders import json_encoder

class GetRequest(BaseModel):
    attr_one: str
    attr_two: int

class Response(BaseModel):
    attr_three: int
    attr_four: str

# url for a running GQL server
client = GraphQLClient(gql_uri="http://localhost:8080/graphql")
query_params = GetRequest(attr_one="foo", attr_two=3)
query = client.get_query(query_base="baseType", query_response_cls=Response, query_parameters=wrap_request(query_params))
print(query)
# {'query': '{baseType(filterParams: {attr_one: "foo", attr_two: 3}){attr_three, attr_four} }'}
pseudo_response = client.execute_gql_query(query_base="baseType", query_response_cls=Response, query_parameters=wrap_request(query_params))
print(pseudo_response)
# [Response(attr_three=5, attr_four="bar")]

Mutation

# limited to pydantic V2
from pydantic import BaseModel

from gqlclient import GraphQLClient


class MutationRequest(BaseModel):
    attr_one: str
    attr_two: int


class Response(BaseModel):
    attr_three: int
    attr_four: str

# url for a running GQL server
client = GraphQLClient(gql_uri="http://localhost:8080/graphql")
mutation_params = MutationRequest(attr_one="foo", attr_two=3)
mutation = client.get_mutation(mutation_base="baseMutation", mutation_response_cls=Response, mutation_parameters=wrap_request(mutation_params))
print(mutation)
# {'query': 'mutation baseMutation {baseMutation(baseMuParams: {attr_one: "foo", attr_two: 3}){attr_three, attr_four} }', 'operationName': 'baseMutation'}

pseudo_response = client.execute_gql_mutation(mutation_base="baseMutation", mutation_response_cls=Response, mutation_parameters=wrap_request(mutation_params))
print(pseudo_response)
# [Response(attr_three=5, attr_four="bar")]

Encoders

# limited to pydantic V2
from pydantic import BaseModel

from gqlclient import GraphQLClient
from gqlclient import json_encoder

# url for a running GQL server
# set the default encoder to the json_encoder
client = GraphQLClient(gql_uri="http://localhost:8080/graphql", default_response_encoder=json_encoder)

class QueryResponse(BaseModel):
    workflowId: int
    workflowName: str
    workflowDescription: str | None = None

response = client.execute_gql_query("workflows",QueryResponse)
print(response)
# Response is a json formatted string
# {"workflows": [{"workflowId": 1, "workflowName": "gql3_full - workflow_name", "workflowDescription": "gql3_full - workflow_description"}, {"workflowId": 2, "workflowName": "VBI base calibration", "workflowDescription": "The base set of calibration tasks for VBI."}]}

from gqlclient import basemodel_encoder
# for this call override the default encoder
response = client.execute_gql_query("workflows", QueryResponse, response_encoder=basemodel_encoder)
print(response)
# Response type is a list of BaseModels
# [QueryResponse(workflowId=1, workflowName='gql3_full - workflow_name', workflowDescription='gql3_full - workflow_description'), QueryResponse(workflowId=2, workflowName='VBI base calibration', workflowDescription='The base set of calibration tasks for VBI.')]

Best Practices

Simple Conversions between Camel Case and Snake Case

If your target GQL endpoint uses camelCase, follow these steps.

First, create a CamelHelper class:

# limited to pydantic V2
from pydantic import BaseModel
from pydantic import ConfigDict
from pydantic.alias_generators import to_camel


class CamelHelper(BaseModel):
    """
    Helper Class.
    Extend this class as if it were BaseModel.
    Within the subclass, define the fields using snake_case.
    Upon BaseModel instantiation, either snake_case or camelCase is valid input.
    Normal model_dump will create a dict with snake_case keys.
    Alias model_dump, with `by_alias=True`, will create a dict with camelCase keys.
    """
    model_config = ConfigDict(
        alias_generator=to_camel,
        populate_by_name=True,
    )

When defining your models, extend CamelHelper, instead of BaseModel. Define the attributes using snake_case.

class AliasSample(CamelHelper):
    required_str: str
    optional_float: float | None = None

# camelCase accepted upon creation
alias_sample = AliasSample(requiredStr="hello")

The internal key names will be snake_case. You can dump to a dict with snake_case keys:

alias_data_snake: dict = alias_sample.model_dump()

Or you can dump to a dict with camelCase keys:

alias_data_camel: dict = alias_sample.model_dump(by_alias=True)

Passing a dict as a dict

To pass a dict as a dict, the GQL Server must define the data type of the corresponding field as JSON. Note that JSON and JSONString are not the same thing. JSONString expects a json encoded string (frequently via json.dumps) which is transformed via json.loads. JSON expects an object and no transformation occurs.

Define the field as a dict within the model:

# limited to pydantic V2
from pydantic import BaseModel

class SampleCreateRequest(CamelHelper):
    required_str:  str | None = "Awesome"
    payload: dict | None = None

dummy_payload = {
    "key_str": "Party On, Wayne",
    "key_int": 42,
    "key_float": 3.141592,
    "key_none": None,
    "key_true": True,
    "key_false": False,
}
create_request = SampleCreateRequest(
    payload = dummy_payload
    )

Execute the request:

# sample response
class SampleResponse(CamelHelper):
    payload: dict | None = None

# url for a running GQL server
client = GraphQLClient(gql_uri="http://localhost:8080/graphql")

# assuming GQL server defines `payload` as `JSON`
pseudo_response = client.execute_gql_mutation(
   mutation_base="sampleMutation",
   mutation_response_cls=SampleResponse,
   mutation_parameters=wrap_request(create_request)
)

assert isinstance(create_request.payload, dict)
assert isinstance(pseudo_response.payload, dict)
assert create_request.payload == pseudo_response.payload

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gqlclient-2.0.0.tar.gz (28.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gqlclient-2.0.0-py3-none-any.whl (30.5 kB view details)

Uploaded Python 3

File details

Details for the file gqlclient-2.0.0.tar.gz.

File metadata

  • Download URL: gqlclient-2.0.0.tar.gz
  • Upload date:
  • Size: 28.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for gqlclient-2.0.0.tar.gz
Algorithm Hash digest
SHA256 e96004d15b1a4af204f32b8d3b611f1e8d9524f9a1ebd6101e50fecb1337281e
MD5 5fa0aca8eb1cd86323bae05201dc062d
BLAKE2b-256 f458ec82b06695eeb0d93bda7d65052404015f72c607531ededc6aec7bba47b9

See more details on using hashes here.

File details

Details for the file gqlclient-2.0.0-py3-none-any.whl.

File metadata

  • Download URL: gqlclient-2.0.0-py3-none-any.whl
  • Upload date:
  • Size: 30.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for gqlclient-2.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4bfe7161c21cc083c3a116faacd258cddbd0217eac6e78d13a41315cae652c5d
MD5 846386cfe090b49bad2b78dff09e2ac1
BLAKE2b-256 8f878692272053aeb595fd32321da25e1964d71844120fb5b78fb4402979657f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page