install 

pip install Sanic-GraphQL

Usage

Use the GraphQLView view fromsanic_graphql

from sanic_graphql import GraphQLView
from sanic import Sanic

from schema import schema

app = Sanic(name="Sanic Graphql App")

app.add_route(
    GraphQLView.as_view(schema=schema, graphiql=True),
    '/graphql'
)

# Optional, for adding batch query support (used in Apollo-Client)
app.add_route(
    GraphQLView.as_view(schema=schema, batch=True),
    '/graphql/batch'
)

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8000)

tests

app.py 

from urllib.parse import urlencode

from sanic import Sanic
from sanic.testing import SanicTestClient

from sanic_graphql import GraphQLView

from .schema import Schema


def create_app(path="/graphql", **kwargs):
    app = Sanic(__name__)
    app.debug = True

    schema = kwargs.pop("schema", None) or Schema
    app.add_route(GraphQLView.as_view(schema=schema, **kwargs), path)

    app.client = SanicTestClient(app)
    return app


def url_string(uri="/graphql", **url_params):
    string = "/graphql"

    if url_params:
        string += "?" + urlencode(url_params)

    return string

schema.py

import asyncio

from graphql.type.definition import (GraphQLArgument, GraphQLField,
                                     GraphQLNonNull, GraphQLObjectType)
from graphql.type.scalars import GraphQLString
from graphql.type.schema import GraphQLSchema


def resolve_raises(*_):
    raise Exception("Throws!")


# Sync schema
QueryRootType = GraphQLObjectType(
    name="QueryRoot",
    fields={
        "thrower": GraphQLField(GraphQLNonNull(GraphQLString), resolve=resolve_raises),
        "request": GraphQLField(
            GraphQLNonNull(GraphQLString),
            resolve=lambda obj, info: info.context["request"].args.get("q"),
        ),
        "context": GraphQLField(
            GraphQLObjectType(
                name="context",
                fields={
                    "session": GraphQLField(GraphQLString),
                    "request": GraphQLField(
                        GraphQLNonNull(GraphQLString),
                        resolve=lambda obj, info: info.context["request"],
                    ),
                },
            ),
            resolve=lambda obj, info: info.context,
        ),
        "test": GraphQLField(
            type_=GraphQLString,
            args={"who": GraphQLArgument(GraphQLString)},
            resolve=lambda obj, info, who=None: "Hello %s" % (who or "World"),
        ),
    },
)

MutationRootType = GraphQLObjectType(
    name="MutationRoot",
    fields={
        "writeTest": GraphQLField(type_=QueryRootType, resolve=lambda *_: QueryRootType)
    },
)

Schema = GraphQLSchema(QueryRootType, MutationRootType)


# Schema with async methods
async def resolver_field_async_1(_obj, info):
    await asyncio.sleep(0.001)
    return "hey"


async def resolver_field_async_2(_obj, info):
    await asyncio.sleep(0.003)
    return "hey2"


def resolver_field_sync(_obj, info):
    return "hey3"


AsyncQueryType = GraphQLObjectType(
    name="AsyncQueryType",
    fields={
        "a": GraphQLField(GraphQLString, resolve=resolver_field_async_1),
        "b": GraphQLField(GraphQLString, resolve=resolver_field_async_2),
        "c": GraphQLField(GraphQLString, resolve=resolver_field_sync),
    },
)

AsyncSchema = GraphQLSchema(AsyncQueryType)

graphiqlview.py

 

import pytest
from jinja2 import Environment

from .app import create_app, url_string
from .schema import AsyncSchema


@pytest.fixture
def pretty_response():
    return (
        "{\n"
        '  "data": {\n'
        '    "test": "Hello World"\n'
        "  }\n"
        "}".replace('"', '\\"').replace("\n", "\\n")
    )


@pytest.mark.parametrize("app", [create_app(graphiql=True)])
def test_graphiql_is_enabled(app):
    _, response = app.client.get(
        uri=url_string(query="{test}"), headers={"Accept": "text/html"}
    )
    assert response.status == 200


@pytest.mark.parametrize("app", [create_app(graphiql=True)])
def test_graphiql_simple_renderer(app, pretty_response):
    _, response = app.client.get(
        uri=url_string(query="{test}"), headers={"Accept": "text/html"}
    )
    assert response.status == 200
    assert pretty_response in response.body.decode("utf-8")


@pytest.mark.parametrize("app", [create_app(graphiql=True, jinja_env=Environment())])
def test_graphiql_jinja_renderer(app, pretty_response):
    _, response = app.client.get(
        uri=url_string(query="{test}"), headers={"Accept": "text/html"}
    )
    assert response.status == 200
    assert pretty_response in response.body.decode("utf-8")


@pytest.mark.parametrize(
    "app", [create_app(graphiql=True, jinja_env=Environment(enable_async=True))]
)
def test_graphiql_jinja_async_renderer(app, pretty_response):
    _, response = app.client.get(
        uri=url_string(query="{test}"), headers={"Accept": "text/html"}
    )
    assert response.status == 200
    assert pretty_response in response.body.decode("utf-8")


@pytest.mark.parametrize("app", [create_app(graphiql=True)])
def test_graphiql_html_is_not_accepted(app):
    _, response = app.client.get(
        uri=url_string(), headers={"Accept": "application/json"}
    )
    assert response.status == 400


@pytest.mark.parametrize(
    "app", [create_app(graphiql=True, schema=AsyncSchema, enable_async=True)]
)
def test_graphiql_asyncio_schema(app):
    query = "{a,b,c}"
    _, response = app.client.get(
        uri=url_string(query=query), headers={"Accept": "text/html"}
    )

    expected_response = (
        (
            "{\n"
            '  "data": {\n'
            '    "a": "hey",\n'
            '    "b": "hey2",\n'
            '    "c": "hey3"\n'
            "  }\n"
            "}"
        )
        .replace('"', '\\"')
        .replace("\n", "\\n")
    )

    assert response.status == 200
    assert expected_response in response.body.decode("utf-8")

keywords: pythonsanic