Skip to content

GraphQL Overview

apischema supports GraphQL through the graphql-core library.

You can install this dependency directly with apischema using the following extra requirement:

pip install apischema[graphql]

GraphQL supports consists of generating a GraphQL schema graphql.GraphQLSchema from your data model and endpoints (queries/mutations/subscribtions), in a similar way than the JSON schema generation. This schema can then be used through graphql-core library to query/mutate/subscribe.

from dataclasses import dataclass
from datetime import date, datetime
from typing import Collection
from uuid import UUID, uuid4

from graphql import graphql_sync, print_schema

from apischema.graphql import graphql_schema, resolver


@dataclass
class User:
    id: UUID
    username: str
    birthday: date | None = None

    @resolver
    def posts(self) -> Collection["Post"]:
        return [post for post in POSTS if post.author.id == self.id]


@dataclass
class Post:
    id: UUID
    author: User
    date: datetime
    content: str


USERS = [User(uuid4(), "foo"), User(uuid4(), "bar")]
POSTS = [Post(uuid4(), USERS[0], datetime.now(), "Hello world!")]


def users() -> Collection[User]:
    return USERS


def posts() -> Collection[Post]:
    return POSTS


def user(username: str) -> User | None:
    for user in users():
        if user.username == username:
            return user
    else:
        return None


schema = graphql_schema(query=[users, user, posts], id_types={UUID})
schema_str = """\
type Query {
  users: [User!]!
  user(username: String!): User
  posts: [Post!]!
}

type User {
  id: ID!
  username: String!
  birthday: Date
  posts: [Post!]!
}

scalar Date

type Post {
  id: ID!
  author: User!
  date: Datetime!
  content: String!
}

scalar Datetime"""
assert print_schema(schema) == schema_str

query = """
{
  users {
    username
    posts {
        content
    }
  }
}"""
assert graphql_sync(schema, query).data == {
    "users": [
        {"username": "foo", "posts": [{"content": "Hello world!"}]},
        {"username": "bar", "posts": []},
    ]
}

GraphQL is fully integrated with the rest of apischema features, especially conversions, so it's easy to integrate ORM and other custom types in the generated schema; this concerns query results but also arguments.

By the way, while GraphQL doesn't support constraints, apischema still offers you all the power of its validation feature. In fact, apischema deserialize and validate all the arguments passed to resolvers.

FAQ

Is it possible to use the same classes to do both GraphQL and REST-API?

Yes it is. GraphQL has some restrictions in comparison to JSON schema (see next section), but this taken in account, all of your code can be reused. In fact, GraphQL endpoints can also be used both by a GraphQL API and a more traditional REST or RPC API.