Skip to content

Latest commit

 

History

History
501 lines (384 loc) · 11.3 KB

EXAMPLE.md

File metadata and controls

501 lines (384 loc) · 11.3 KB

Example

Schema file

schema {
  query: Query
  mutation: Mutation
}

type Query {
  users(country: String): [User!]!
}

type Subscription {
  usersCounter: Int!
}

type Mutation {
  userCreate(userData: UserCreateInput!): User
  userPreferences(data: UserPreferencesInput): Boolean!
}

input UserCreateInput {
  firstName: String
  lastName: String
  email: String!
  favouriteColor: Color 
  location: LocationInput
}

input LocationInput {
  city: String
  country: String
}

type User {
  id: ID!
  firstName: String
  lastName: String
  email: String!
  favouriteColor: Color 
  location: Location
}

type Location {
  city: String
  country: String
}

enum Color {
  BLACK
  WHITE
  RED
  GREEN
  BLUE
  YELLOW
}

input UserPreferencesInput {
  luckyNumber: Int = 7
  favouriteWord: String = "word"
  colorOpacity: Float = 1.0
  excludedTags: [String!] = ["offtop", "tag123"]
  notificationsPreferences: NotificationsPreferencesInput! = {receiveMails: true, receivePushNotifications: true, receiveSms: false, title: "Mr"}
}

input NotificationsPreferencesInput {
  receiveMails: Boolean!
  receivePushNotifications: Boolean!
  receiveSms: Boolean!
  title: String!
}

Queries/mutations/subscriptions file

mutation CreateUser($userData: UserCreateInput!) {
    userCreate(userData: $userData) {
        id
    }
}

query ListAllUsers {
    users {
        id
        firstName
        lastName
        email
        location {
            country
        }
    }
}

query ListUsersByCountry($country: String) {
    users(country: $country) {
        ...BasicUser
        ...UserPersonalData
        favouriteColor
    }
}

fragment BasicUser on User {
    id
    email
}

fragment UserPersonalData on User {
    firstName
    lastName
}

subscription GetUsersCounter {
    usersCounter
}

Running

Add [tool.ariadne-codegen] section to pyproject.toml with paths to files with schema and queries/mutations.

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

Run command to generate code:

$ ariadne-codegen

Result

Generated files

Structure of generated package:

grapql_client/
    __init__.py
    async_base_client.py
    base_model.py
    client.py
    create_user.py
    enums.py
    exceptions.py
    get_users_counter.py
    input_types.py
    list_all_users.py
    list_users_by_country.py
    scalars.py

Client class

Generated client class inherits from AsyncBaseClient and has async method for every provided query/mutation.

# graphql_client/client.py

from typing import AsyncIterator, Optional, Union

from .async_base_client import AsyncBaseClient
from .base_model import UNSET, UnsetType
from .create_user import CreateUser
from .get_users_counter import GetUsersCounter
from .input_types import UserCreateInput
from .list_all_users import ListAllUsers
from .list_users_by_country import ListUsersByCountry


def gql(q: str) -> str:
    return q


class Client(AsyncBaseClient):
    async def create_user(self, user_data: UserCreateInput) -> CreateUser:
        query = gql(
            """
            mutation CreateUser($userData: UserCreateInput!) {
              userCreate(userData: $userData) {
                id
              }
            }
            """
        )
        variables: dict[str, object] = {"userData": user_data}
        response = await self.execute(query=query, variables=variables)
        data = self.get_data(response)
        return CreateUser.parse_obj(data)

    async def list_all_users(self) -> ListAllUsers:
        query = gql(
            """
            query ListAllUsers {
              users {
                id
                firstName
                lastName
                email
                location {
                  country
                }
              }
            }
            """
        )
        variables: dict[str, object] = {}
        response = await self.execute(query=query, variables=variables)
        data = self.get_data(response)
        return ListAllUsers.parse_obj(data)

    async def list_users_by_country(
        self, country: Union[Optional[str], UnsetType] = UNSET
    ) -> ListUsersByCountry:
        query = gql(
            """
            query ListUsersByCountry($country: String) {
              users(country: $country) {
                ...BasicUser
                ...UserPersonalData
                favouriteColor
              }
            }

            fragment BasicUser on User {
              id
              email
            }

            fragment UserPersonalData on User {
              firstName
              lastName
            }
            """
        )
        variables: dict[str, object] = {"country": country}
        response = await self.execute(query=query, variables=variables)
        data = self.get_data(response)
        return ListUsersByCountry.parse_obj(data)

    async def get_users_counter(self) -> AsyncIterator[GetUsersCounter]:
        query = gql(
            """
            subscription GetUsersCounter {
              usersCounter
            }
            """
        )
        variables: dict[str, object] = {}
        async for data in self.execute_ws(query=query, variables=variables):
            yield GetUsersCounter.parse_obj(data)

Base client

Base client is copied from path provided in base_client_file_path and has to contain definition of class with name provided in base_client_name.

Base model

base_model.py is a file that contains preconfigured class, which extends pydantic's BaseModel class and is used by other generated classes.

Input types

Models are generated from inputs from provided schema. They are used as arguments types in client`s methods.

# graphql_client/input_types.py

from typing import List, Optional

from pydantic import Field

from .base_model import BaseModel
from .enums import Color


class UserCreateInput(BaseModel):
    first_name: Optional[str] = Field(alias="firstName")
    last_name: Optional[str] = Field(alias="lastName")
    email: str
    favourite_color: Optional[Color] = Field(alias="favouriteColor")
    location: Optional["LocationInput"]


class LocationInput(BaseModel):
    city: Optional[str]
    country: Optional[str]


class UserPreferencesInput(BaseModel):
    lucky_number: Optional[int] = Field(alias="luckyNumber", default=7)
    favourite_word: Optional[str] = Field(alias="favouriteWord", default="word")
    color_opacity: Optional[float] = Field(alias="colorOpacity", default=1.0)
    excluded_tags: Optional[List[str]] = Field(
        alias="excludedTags", default_factory=lambda: ["offtop", "tag123"]
    )
    notifications_preferences: "NotificationsPreferencesInput" = Field(
        alias="notificationsPreferences",
        default_factory=lambda: globals()["NotificationsPreferencesInput"].parse_obj(
            {
                "receiveMails": True,
                "receivePushNotifications": True,
                "receiveSms": False,
                "title": "Mr",
            }
        ),
    )


class NotificationsPreferencesInput(BaseModel):
    receive_mails: bool = Field(alias="receiveMails")
    receive_push_notifications: bool = Field(alias="receivePushNotifications")
    receive_sms: bool = Field(alias="receiveSms")
    title: str


UserCreateInput.update_forward_refs()
LocationInput.update_forward_refs()
UserPreferencesInput.update_forward_refs()
NotificationsPreferencesInput.update_forward_refs()

Enums

Enums are generated from enums from provided schema. They are used in other generated classes as field types, but also as arguments types in client`s methods.

# graphql_client/enums.py

from enum import Enum


class Color(str, Enum):
    BLACK = "BLACK"
    WHITE = "WHITE"
    RED = "RED"
    GREEN = "GREEN"
    BLUE = "BLUE"
    YELLOW = "YELLOW"

Query/mutation/subscription types

For every provided query/mutation/subscription there is a generated file that contains models which correspond to return type of operation. File name is generated by converting operation name to snake case. Root models has the same name as query/mutation/subscription, and depend classes use it as prefix in their names.

# graphql_client/create_user.py

from typing import Optional

from pydantic import Field

from .base_model import BaseModel


class CreateUser(BaseModel):
    user_create: Optional["CreateUserUserCreate"] = Field(alias="userCreate")


class CreateUserUserCreate(BaseModel):
    id: str


CreateUser.update_forward_refs()
CreateUserUserCreate.update_forward_refs()
# graphql_client/list_all_users.py

from typing import List, Optional

from pydantic import Field

from .base_model import BaseModel


class ListAllUsers(BaseModel):
    users: List["ListAllUsersUsers"]


class ListAllUsersUsers(BaseModel):
    id: str
    first_name: Optional[str] = Field(alias="firstName")
    last_name: Optional[str] = Field(alias="lastName")
    email: str
    location: Optional["ListAllUsersUsersLocation"]


class ListAllUsersUsersLocation(BaseModel):
    country: Optional[str]


ListAllUsers.update_forward_refs()
ListAllUsersUsers.update_forward_refs()
ListAllUsersUsersLocation.update_forward_refs()
# graphql_client/list_users_by_country.py

from typing import List, Optional

from pydantic import Field

from .base_model import BaseModel
from .enums import Color


class ListUsersByCountry(BaseModel):
    users: List["ListUsersByCountryUsers"]


class ListUsersByCountryUsers(BaseModel):
    id: str
    email: str
    first_name: Optional[str] = Field(alias="firstName")
    last_name: Optional[str] = Field(alias="lastName")
    favourite_color: Optional[Color] = Field(alias="favouriteColor")


ListUsersByCountry.update_forward_refs()
ListUsersByCountryUsers.update_forward_refs()
# graphql_client/get_users_counter.py

from pydantic import Field

from .base_model import BaseModel


class GetUsersCounter(BaseModel):
    users_counter: int = Field(alias="usersCounter")


GetUsersCounter.update_forward_refs()

Init file

Generated init file contains reimports and list of all generated classes.

# graphql_client/__init__.py

from .async_base_client import AsyncBaseClient
from .base_model import BaseModel
from .client import Client
from .create_user import CreateUser, CreateUserUserCreate
from .enums import Color
from .exceptions import (
    GraphQLClientError,
    GraphQLClientGraphQLError,
    GraphQLClientGraphQLMultiError,
    GraphQLClientHttpError,
    GraphQlClientInvalidResponseError,
)
from .get_users_counter import GetUsersCounter
from .input_types import (
    LocationInput,
    NotificationsPreferencesInput,
    UserCreateInput,
    UserPreferencesInput,
)
from .list_all_users import ListAllUsers, ListAllUsersUsers, ListAllUsersUsersLocation
from .list_users_by_country import ListUsersByCountry, ListUsersByCountryUsers

__all__ = [
    "AsyncBaseClient",
    "BaseModel",
    "Client",
    "Color",
    "CreateUser",
    "CreateUserUserCreate",
    "GetUsersCounter",
    "GraphQLClientError",
    "GraphQLClientGraphQLError",
    "GraphQLClientGraphQLMultiError",
    "GraphQLClientHttpError",
    "GraphQlClientInvalidResponseError",
    "ListAllUsers",
    "ListAllUsersUsers",
    "ListAllUsersUsersLocation",
    "ListUsersByCountry",
    "ListUsersByCountryUsers",
    "LocationInput",
    "NotificationsPreferencesInput",
    "UserCreateInput",
    "UserPreferencesInput",
]