• Stars
    star
    203
  • Rank 186,820 (Top 4 %)
  • Language
    Python
  • License
    BSD 3-Clause "New...
  • Created over 1 year ago
  • Updated 25 days ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Generate fully typed Python client for any GraphQL API from schema, queries and mutations

Ariadne

Build Status


Ariadne Code Generator

Python code generator that takes graphql schema, queries, mutations and subscriptions and generates Python package with fully typed and asynchronous GraphQL client.

It's available as ariadne-codegen command and reads configuration from the pyproject.toml file:

$ ariadne-codegen

It can also be run as python -m ariadne_codegen.

Features

  • Generate pydantic models from schema types, inputs and enums.
  • Generate pydantic models for GraphQL results.
  • Generate client package with each GraphQL operation available as async method.

Installation

Ariadne Code Generator can be installed with pip:

$ pip install ariadne-codegen

To support subscriptions, default base client requires websockets package:

$ pip install ariadne-codegen[subscriptions]

Configuration

ariadne-codegen reads configuration from [tool.ariadne-codegen] section in your pyproject.toml. You can use other configuration file with --config option, eg. ariadne-codegen --config custom_file.toml

Minimal configuration for client generation:

[tool.ariadne-codegen]
schema_path = "schema.graphql"
queries_path = "queries.graphql"

Required settings:

  • queries_path - path to file/directory with queries

One of the following 2 parameters is required, in case of providing both of them schema_path is prioritized:

  • schema_path - path to file/directory with graphql schema
  • remote_schema_url - url to graphql server, where introspection query can be perfomed

Optional settings:

  • remote_schema_headers - extra headers that are passed along with introspection query, eg. {"Authorization" = "Bearer: token"}. To include an environment variable in a header value, prefix the variable with $, eg. {"Authorization" = "$AUTH_TOKEN"}
  • remote_schema_verify_ssl (defaults to true) - a flag that specifies wheter to verify ssl while introspecting remote schema
  • target_package_name (defaults to "graphql_client") - name of generated package
  • target_package_path (defaults to cwd) - path where to generate package
  • client_name (defaults to "Client") - name of generated client class
  • client_file_name (defaults to "client") - name of file with generated client class
  • base_client_name (defaults to "AsyncBaseClient") - name of base client class
  • base_client_file_path (defaults to .../graphql_sdk_gen/generators/async_base_client.py) - path to file where base_client_name is defined
  • enums_module_name (defaults to "enums") - name of file with generated enums models
  • input_types_module_name (defaults to "input_types") - name of file with generated input types models
  • fragments_module_name (defaults to "fragments") - name of file with generated fragments models
  • include_comments (defaults to true) - a flag that specifies whether to include comments in generated files
  • convert_to_snake_case (defaults to true) - a flag that specifies whether to convert fields and arguments names to snake case
  • async_client (defaults to true) - default generated client is async, change this to option false to generate synchronous client instead
  • files_to_include (defaults to []) - list of files which will be copied into generated package
  • plugins (defaults to []) - list of plugins to use during generation

Plugins

Ariadne Codegen implements a plugin system that enables further customization and fine-tuning of generated Python code. It’s documentation is available separately in the PLUGINS.md file.

Standard plugins

Ariadne Codegen ships with optional plugins importable from the ariadne_codegen.contrib package:

  • ariadne_codegen.contrib.shorter_results.ShorterResultsPlugin - This plugin processes generated client methods for operations where only single top field is requested, so they return this field's value directly instead of operation's result type. For example get_user method generated for query GetUser() { user(...) { ... }} will return value of user field directly instead of GetUserResult.

Using generated client

Generated client can be imported from package:

from {target_package_name}.{client_file_name} import {client_name}

Example with default settings:

from graphql_client.client import Client

Passing headers to client

Client (with default base client), takes passed headers and attaches them to every sent request.

client = Client("https://example.com/graphql", {"Authorization": "Bearer token"})

For more complex scenarios, you can pass your own http client:

client = Client(http_client=CustomComplexHttpClient())

CustomComplexHttpClient needs to be an instance of httpx.AsyncClient for async client, or httpx.Client for sync.

Websockets

To handle subscriptions, default AsyncBaseClient uses websockets and implements graphql-transport-ws subprotocol. Arguments ws_origin and ws_headers are added as headers to the handshake request and ws_connection_init_payload is used as payload of ConnectionInit message.

File upload

Default base client (AsyncBaseClient or BaseClient) checks if any part of variables dictionary is an instance of Upload. If at least one instance is found then client sends multipart request according to GraphQL multipart request specification.

Dataclass Upload is included in generated client and can be imported from it:

from {target_package_name} import Upload

By default we use this class to represent graphql scalar Upload. For schema with different name for this scalar, you can still use Upload and default client for file uploads:

[tool.ariadne-codegen.scalars.OTHERSCALAR]
type = "Upload"

Custom scalars

By default, not built-in scalars are represented as typing.Any in generated client. You can provide information about specific scalar by adding section to pyproject.toml:

[tool.ariadne-codegen.scalars.{graphql scalar name}]
type = "(required) python type name"
serialize = "function used to serialize scalar"
parse = "function used to create scalar instance from serialized form"

All occurrences of {graphql scalar name} will be represented as type. If provided, serialize and parse will be used for serialization and deserialization. If type/serialize/parse contains at least one . then string will be split by it's last occurrence. First part will be used as module to import from, and second part as type/method name. For example, type = "custom_scalars.a.ScalarA" will produce from custom_scalars.a import ScalarA.

Example with scalar mapped to built-in type

In this case scalar is mapped to built-in str which doesn't require custom serialize and parse methods.

[tool.ariadne-codegen.scalars.SCALARA]
type = "str"

Example with type supported by pydantic

In this scenario scalar is represented as datetime, so it needs to be imported. Pydantic handles serialization and deserialization so custom parse and serialize is not necessary.

[tool.ariadne-codegen.scalars.DATETIME]
type = "datetime.datetime"

Example with fully custom type

In this example scalar is represented as class TypeB. Pydantic can`t handle serialization and deserialization so custom parse and serialize is necessary. To provide type, parse and serialize implementation we can use files_to_include to copy type_b.py file.

[tool.ariadne-codegen]
...
files_to_include = [".../type_b.py"]

[tool.ariadne-codegen.scalars.SCALARB]
type = ".type_b.TypeB"
parse = ".type_b.parse_b"
serialize = ".type_b.serialize_b"

Extending generated types

Extending models with custom mixins

mixin directive allows to extend class generated for query/mutation field with custom logic. mixin takes two required arguments:

  • from - name of a module to import from
  • import - name of a parent class

Generated class will use import as extra base class, and import will be added to the file.

from {from} import {import}
...
class OperationNameField(BaseModel, {import}):
    ...

This directive can be used along with files_to_include option to extend functionality of generated classes.

Example of usage of mixin and files_to_include:

Query with mixin directive:

query listUsers {
    users @mixin(from: ".mixins", import: "UsersMixin") {
        id
    }
}

Part of pyproject.toml with files_to_include (mixins.py contains UsersMixin implementation)

files_to_include = [".../mixins.py"]

Part of generated list_users.py file:

...
from .mixins import UsersMixin
...
class ListUsersUsers(BaseModel, UsersMixin):
    ...

Multiple clients

To generate multiple different clients you can store config for each in different file, then provide path to config file by --config option, eg.

ariadne-codegen --config clientA.toml
ariadne-codegen --config clientB.toml

Generated code dependencies

Generated code requires:

Both httpx and websockets dependencies can be avoided by providing another base client class with base_client_file_path and base_client_name options.

Example

Example with simple schema and few queries and mutations is available here.

Generating graphql schema's python representation

Instead of generating client, you can generate file with a copy of GraphQL schema as GraphQLSchema declaration. To do this call ariadne-codegen with graphqlschema argument:

ariadne-codegen graphqlschema

graphqlschema mode reads configuration from the same place as client but uses only schema_path, remote_schema_url, remote_schema_headers, remote_schema_verify_ssl and plugins options with addition to some extra options specific to it:

  • target_file_path (defaults to "schema.py") - destination path for generated file
  • schema_variable_name (defaults to "schema") - name for schema variable, must be valid python identifier
  • type_map_variable_name (defaults to "type_map") - name for type map variable, must be valid python identifier

Generated file contains:

  • Necessary imports
  • Type map declaration {type_map_variable_name}: TypeMap = {...}
  • Schema declaration {schema_variable_name}: GraphQLSchema = GraphQLSchema(...)

Contributing

We welcome all contributions to Ariadne! If you've found a bug or issue, feel free to use GitHub issues. If you have any questions or feedback, don't hesitate to catch us on GitHub discussions.

For guidance and instructions, please see CONTRIBUTING.md.

Also make sure you follow @AriadneGraphQL on Twitter for latest updates, news and random musings!

Crafted with ❤️ by Mirumee Software [email protected]

More Repositories

1

ariadne

Python library for implementing GraphQL servers using schema-first approach.
Python
2,134
star
2

satchless

E-commerce for Python
Python
784
star
3

prices

Python price handling for humans.
Python
267
star
4

django-prices

Django fields for the prices module
Python
157
star
5

google-i18n-address

Google's i18n address data packaged for Python.
Python
130
star
6

google-measurement-protocol

A Python implementation of Google Analytics Measurement Protocol
Python
103
star
7

ariadne-django

ariadne_django makes integrating ariadne and django together easier.
Python
65
star
8

django-images

A database-driven thumbnailing solution for Django
Python
63
star
9

django-messages

A Django application handling private messages between users.
Python
52
star
10

saleor-app-framework-python

Python Saleor App/Extension boilerplate. Batteries included.
Python
49
star
11

chromedebug

A Chrome remote debugging protocol server for Python
Python
36
star
12

ariadne-graphql-modules

Ariadne package for implementing Ariadne GraphQL schemas using modular approach.
Python
34
star
13

django-prices-openexchangerates

openexchangerates.org support for django-prices
Python
33
star
14

ariadne-website

The code that powers Ariadne website
JavaScript
22
star
15

gql-federation-gateway

Simple gateway for Apollo Federation with JWT
JavaScript
18
star
16

django-offsite-storage

Cloud static and media file storage suitable for app containers
Python
18
star
17

serverless-saleor-app-example

Example implementation of Saleor app using AWS Lambda
Python
17
star
18

django-prices-vatlayer

Vatlayer API support for django-prices
Python
15
star
19

django-voice

A simple user feedback application for your Django project
Python
14
star
20

bestest

Some of the bestest™ and cleverestest™ code out there
Python
14
star
21

legacy-views

A legacy fork of Saleor that contains the old storefront and dashboard code
Python
14
star
22

graphql-workshop

A GraphQL workshop for DjangoCon EU 2019
Python
13
star
23

django-bootstrap-mockups

A template mocking tool for Django
Python
11
star
24

overv.io-beta

Private beta feedback
11
star
25

django-ariadne-deprecated

Django bindings for the Ariadne GraphQL library.
11
star
26

ariadne-graphql-proxy

Ariadne toolkit for building GraphQL proxies.
Python
11
star
27

trapecssoid

CSS-based trapezoid blocks
CSS
10
star
28

saleor-demo

Saleor's demo setup
HTML
10
star
29

ariadne-graphql-chat-example

Simple Chat application using Ariadne and GraphQL Subscriptions
JavaScript
4
star
30

subgraph-template-ariadne-fastapi

Python
4
star
31

codeclimate-isort

An isort plugin for codeclimate
Python
3
star
32

opentracing-asgi

ASGI middleware reporting to the OpenTracing API
Python
3
star
33

saleor-product-mockups

Free Saleor product templates
3
star
34

saleor-sdk-python

Python
3
star
35

python-invoicible

Invoicible/CentrumFaktur library that provides pure Python interface to CentrumFaktur API
Python
2
star
36

overv.io-splash

Overv.io public webpage
HTML
1
star
37

graphql-wroclaw-website

GraphQL Wrocław Meetup
JavaScript
1
star
38

saleor-graphql-deprecations

Deprecations tracker for Saleor's GraphQL API
Python
1
star
39

js-invoicible

Invoicible/CentrumFaktur library that provides JavaScript interface to CentrumFaktur API
JavaScript
1
star
40

aws_secrets_cache

Cache AWS Secrets
Python
1
star
41

saleor-algolia-demo

Python
1
star
42

smyth

A versatile tool that enhances your AWS Lambda development experience.
Python
1
star