home shape

Auto-Generate GraphQL for ArangoDB

Currently, querying ArangoDB with GraphQL requires building a GraphQL.js schema. This is tedious and the resulting JavaScript schema file can be long and bulky. Here we will demonstrate a short proof of concept that reduces the user related part to only defining the GraphQL IDL file and simple AQL queries.

The Apollo GraphQL project built a library that takes a GraphQL IDL and resolver functions to build a GraphQL.js schema. Resolve functions are called by GraphQL to get the actual data from the database. I modified the library in the way that before the resolvers are added, I read the IDL AST and create resolver functions.

To simplify things and to not depend on special “magic”, let’s introduce the directive `@aql`. With this directive, it’s possible to write an AQL query that gets the needed data. With the bind parameter `@current` it is possible to access the current parent object to do JOINs or related operations.

New to multi-model and graphs? Check out our free ArangoDB Graph Course.

Interested in trying out ArangoDB? Fire up your database in just a few clicks with ArangoDB ArangoGraph: the Cloud Service for ArangoDB. Start your free 14-day trial here.

A GraphQL IDL

type BlogEntry {
  _key: String!
  authorKey: String!

  author: Author @aql(exec: "FOR author IN Author FILTER author._key == @current.authorKey RETURN author")
}

type Author {
  _key: String!
  name: String
}

type Query {
  blogEntry(_key: String!): BlogEntry
}

This IDL describes a `BlogEntry` and an `Author` object. The `BlogEntry` holds an `Author` object which is fetched via the AQL query in the directive `@aql`. The type Query defines a query that fetches one `BlogEntry`.

Now let’s have a look at a GraphQL query:

{
  blogEntry(_key: "1") {
    _key
    authorKey
    author {
      name
    }
  }
}

This query fetches the `BlogEntry` with `_key` “1”. The generated AQL query is:

FOR doc IN BlogEntry FILTER doc._key == '1' RETURN doc

And with the fetched `BlogEntry` document the corresponding `Author` is fetched via the AQL query defined in the directive.

The result will approximately look like this:

{
  "data" : {
    "blogEntry" : {
      "_key" : "1",
      "authorKey" : "2",
      "author" : {
        "name" : "Author Name"
      }
    }
  }
}

As a conclusion of this short demo, we can claim that with the usage of GraphQLs IDL, it is possible to reduce effort on the users’ side to query ArangoDB with GraphQL. For simple GraphQL queries and IDLs it’s possible to automatically generate resolvers to fetch the necessary data.

The effort resulted in an npm package is called graphql-aql-generator.

ArangoDB Foxx example

Now let’s have a look at the same example, but with using ArangoDB javascript framework – Foxx. To do so, we have to follow the simple steps listed below:

  1. Open the ArangoDB web interface and navigate to `SERVICES`.
  2. Then click `Add Service`. Select `New Service` and fill out all fields with `*`.
    Important is the `Mount` field. I will use `/test`. Then Generate.
  3. Click on the service to open its settings. Click `Settings` and then go to `Set Development` to enable the development mode.
  4. Then click `Info` and open the path at `Path:`.

Now we have to install the npm package:

npm install --save graphql-aql-generator

We also need the collections `Author` and `BlogEntry`. And the following documents:

  • `Author` collection:
{
  "_key":"2"
  "name": "Author Name"
}
  • `BlogEntry` collection:
{
  "_key":"1"
  "authorKey": "2"
}

Foxx has a built-in graphql router that we can use to serve GraphQL queries. We assemble a new route called `/graphql` that serves the incoming GraphQL queries. With `graphiql: true` we enable the GraphiQL explorer so we can test-drive our queries.

const createGraphQLRouter = require('@arangodb/foxx/graphql');
const generator = require('graphql-aql-generator');

const typeDefs = [`...`]

const schema = generator(typeDefs);

router.use('/graphql', createGraphQLRouter({
schema: schema,
graphiql: true,
graphql: require('graphql-sync')
}));

Open `127.0.0.1:8529/test/graphql` and the GraphiQL explorer is loaded so we can execute a query to fetch a `BlogEntry` with an `Author`.

{
  blogEntry(_key: "1") {
    _key
    authorKey
    author {
	  name
	}
  }
}
```
The result is:

```
{
  "data": {
    "blogEntry": {
	  "_key": "1",
	  "authorKey": "2",
	  "author": {
	    "name": "Author Name"
	  }
    }
  }
}

For the sake of completeness, here is the full Foxx example that works by copy & paste. Do not forget to
`npm install graphql-aql-generator` and create the collections and documents.

// main.js code
'use strict';

const createRouter = require('@arangodb/foxx/router');
const router = createRouter();
module.context.use(router);

const createGraphQLRouter = require('@arangodb/foxx/graphql');
const generator = require('graphql-aql-generator');

const typeDefs = [`
type BlogEntry {
_key: String!
authorKey: String!

author: Author @aql(exec: "FOR author in Author filter author._key == @current.authorKey return author")
}

type Author {
_key: String!
name: String
}

type Query {
blogEntry(_key: String!): BlogEntry
}
`]

const schema = generator(typeDefs);

router.use('/graphql', createGraphQLRouter({
schema: schema,
graphiql: true,
graphql: require('graphql-sync')
}));

Would be great to hear your thoughts, feedback, questions, and comments in our Slack Community channel or via a contact us form.

Frank Celler

Frank Celler

Frank is both entrepreneur and backend developer, developing mostly memory databases for two decades. He is the CTO and co-founder of ArangoDB. Try to challenge Frank asking him questions on C, C++ and MRuby. Besides Frank organizes Cologne’s NoSQL group & is an active member of NoSQL community.

5 Comments

  1. Mustafa Ekim on October 7, 2017 at 6:42 am

    It seems very powerful. Does it create a single query to fetch data?

  2. Olivier BONNAURE on October 9, 2017 at 7:26 pm

    This is awesome 🙂

  3. Sven Bardos on February 5, 2018 at 9:56 am

    Is it possible to support “Subscription” of GraphQL with Foxx?

  4. raquel on June 17, 2021 at 8:00 am

    will this work for Mutation?

Leave a Comment





Get the latest tutorials, blog posts and news: