Posted on

Introducing tartiflette-plugin-scalars

This month I worked on a plugin for the Tartiflette GraphQL engine. It’s called tartiflette-plugin-scalars and it is here to help you validate data using scalar types in your GraphQL schema.

If you’ve never heard of Tartiflette before, it’s Dailymotion’s in-house GraphQL engine in Python 3.6. It aims at offering an SDL-first schema definition, allowing developers to focus on business-critical code. Tartiflette makes use of asyncio and can be used over aiohttp or ASGI.

A tartiflette, with fried ham
Illustraton by Hayford Peirce

Tartiflette-plugin-scalars come with a list of common types such as DateTime, URL or IPv4. Using those types in your GraphQL schema will guarantee that the data you receive, as well as the data you send back, is in the correct format. When possible, the plugin will automatically serialize and unserialize the types you use toward Python3 types, like datetime.datetime.

If you want to start using it right now, you can install it through pip:

pip install tartiflette && pip install tartiflette-plugin-scalars

Then initialize the engine with create_engine, indicating you want to use tartiflette_plugin_scalars and an SDL file.

from tartiflette import create_engine

with open("schema.sdl") as schema:
    engine = await create_engine(
        schema.read(),
        modules=[
            {
                "name": "tartiflette_plugin_scalars",
                "config": {},
            }
        ],
    )

Then you can start using the custom scalars to define your SDL. In the following example, we have a query that can return an IPv4 address with a port and a mutation that accepts a GUID as input and returns it:

type Query {
  ipAddress: IPv4
  port: Port
}

type Mutation {
  checkGUID(input: GUID!): GUID!
}

Write your resolvers as simple functions using the @Resolver decorator:

from tartiflette import Resolver

@Resolver("Query.ipAddress")
async def resolve_ip_address(parent, args, ctx, info):
    return ip_address("127.0.0.1")

@Resolver("Query.port")
async def resolve_port(parent, args, ctx, info):
    return 8080

@Resolver("Mutation.checkGUID")
async def resolve_guid(parent, args, ctx, info):
    return args["input"]

Your program will be ready to accept requests. Tartiflette’s type system will automatically validate the data you resolve in queries and mutations:

>>> await engine.execute("query ip { ipAddress port }")
{'data': {'ipAddress': '127.0.0.1', 'port': 8080}}
>>> await engine.execute("mutation GUID { checkGUID(input:\"1df282eb-a458-4763-a3ca-619c320c5a3e\") }")
{'data': {'checkGUID': '1df282eb-a458-4763-a3ca-619c320c5a3e'}}

If you want to use tartiflette with an HTTP server, the plugin tartiflette-aiohttp is there to help you do this. You can install it by running :

pip install tartiflette-aiohttp

And start your engine with aiohttp using register_graphql_handlers:

from aiohttp import web
from tartiflette_aiohttp import register_graphql_handlers

web.run_app(
    register_graphql_handlers(
        web.Application(),
        engine=engine,
    )
)

The API will be exposed by default on http://localhost:8080/graphql. You can try it with a simple query and HTTPie:

➜ http --json POST http://localhost:8080/graphql \
> query="query ip { ipAddress port }"

HTTP/1.1 200 OK
Content-Length: 50
Content-Type: application/json; charset=utf-8
Date: Thu, 31 Oct 2019 18:24:02 GMT
Server: Python/3.7 aiohttp/3.6.2

{
    "data": {
        "ipAddress": "127.0.0.1",
        "port": 8080
    }
}

As you can see, Tartiflette makes getting started with GraphQL in Python a simple and straightforward process. The full code for this article’s example is available on GitHub as well as Tartiflette source code.