Custom server example

In addition to simple GraphQL server implementation in form of GraphQLMiddleware, Ariadne provides building blocks for assembling custom GraphQL servers.

Creating executable schema

The key piece of the GraphQL server is an executable schema - a schema with resolver functions attached to fields.

Ariadne provides a make_executable_schema utility function that takes type definitions as a first argument and a resolvers map as the second, and returns an executable instance of GraphQLSchema:

from ariadne import make_executable_schema

type_defs = """
    type Query {
        hello: String!
    }
"""


def resolve_hello(_, info):
    request = info.context["environ"]
    user_agent = request.get("HTTP_USER_AGENT", "guest")
    return "Hello, %s!" % user_agent


resolvers = {
    "Query": {
        "hello": resolve_hello
    }
}

schema = make_executable_schema(type_defs, resolvers)

This schema can then be passed to the graphql query executor together with the query and variables:

from graphql import graphql

result = graphql(schema, query, variables={})

Basic GraphQL server with Django

The following example presents a basic GraphQL server using a Django framework:

import json

from ariadne import make_executable_schema
from ariadne.constants import PLAYGROUND_HTML
from django.http import (
    HttpResponse, HttpResponseBadRequest, JsonResponse
)
from django.views import View
from graphql import format_error, graphql

type_defs = """
    type Query {
        hello: String!
    }
"""


def resolve_hello(_, info):
    request = info.context["environ"]
    user_agent = request.get("HTTP_USER_AGENT", "guest")
    return "Hello, %s!" % user_agent


resolvers = {
    "Query": {
        "hello": resolve_hello
    }
}

# Create executable schema instance
schema = make_executable_schema(type_defs, resolvers)


# Create GraphQL view
class GraphQLView(View):
    # On GET request serve GraphQL Playground
    # You don't need to provide Playground if you don't want to
    # bet keep on mind this will nor prohibit clients from
    # exploring your API using desktop GraphQL Playground app.
    def get(self, request, *args, **kwargs):
        return HttpResponse(PLAYGROUND_HTML)

    # GraphQL queries are always sent as POSTd
    def post(self, request, *args, **kwargs):
        # Reject requests that aren't JSON
        if request.content_type != "application/json":
            return HttpResponseBadRequest()

        # Naively read data from JSON request
        try:
            data = json.loads(request.data)
        except ValueError:
            return HttpResponseBadRequest()

        # Check if instance data is not empty and dict
        if not data or not isinstance(data, dict):
            return HttpResponseBadRequest()

        # Check if variables are dict:
        variables = data.get("variables")
        if variables and not isinstance(variables, dict):
            return HttpResponseBadRequest()

        # Execute the query
        result = graphql(
            schema,
            data.get("query"),
            context=request,  # expose request as info.context
            variables=data.get("variables"),
            operation_name=data.get("operationName"),
        )

        # Build valid GraphQL API response
        status = 200
        response = {}
        if result.errors:
            response["errors"] = map(format_error, result.errors)
        if result.invalid:
            status = 400
        else:
            response["data"] = result.data

        # Send response to client
        return JsonResponse(response, status=status)