Getting Started with Neo4j and GraphQL

Whereas GaphQL usually requires you to write resolvers for each operation Neo4j has started two projects on Github which provide "auto-translation" from GraphQL queries to Neo4j's Cypher queries and thus saves the effort to write custom resolvers. And on top there is only a single query to the database.

Although both neo4-graphql and neo4-graphql-js are still in early development it is amazing to see that without much effort in the backend you can provide a lot, varying, and nested data to your frontend without the need to write custom resolver for each GraphQL operation type (e.g. queries or mutations). The approach is comparable to postgraphql which translates a PostgreSQL schema to a GraphQL schema.

New to GraphQL and/or Neo4j? Check out this DZone RefCard or one of these two great videos (webinar or online meetup) by @lyonwj and come back for the rest of this intro.

Basic Setup

All you need is a Neo4j instance with a database and - if using neo4-graphql-js - a NodeJS instance. Both are available as official Docker images.

Overview

You could of course set something up yourself, see the GRAND stack e.g., but regarding the two projects already provided by Neo4j there are basically two options:

  • An embedded GraphQL server as a db extension (neo4-graphql),
  • or an external GraphQL server based on NodeJS (neo4-graphql-js).

neo4-graphql

The Kotlin based neo4j-graphql can be installed as a Neo4j server extension to act as a GraphQL endpoint so that your Neo4j server is the GraphQL server. It then turns GraphQL queries and mutations into Cypher statements and executes them on the Neo4j server.

All you need to do is copy the appropriate .jar file for your server version to the Neo4j plugins directory and set the Neo4j config to allow the plugin as yet unmanaged extension. A basic Dockerfile would then look like this:

FROM neo4j:latest

COPY neo4j-graphql-3.3.0.0.jar /var/lib/neo4j/plugins

RUN echo 'dbms.unmanaged_extension_classes=org.neo4j.graphql=/graphql' | tee -a /var/lib/neo4j/conf/neo4j.conf

CMD ["neo4j"]

After building the image and running the container you can either POST your own schema to /graphql/idl or let the extension build the schema from the graph.

For easy testing you could use graphiql and if you are testing neo4j-graphql-js as well (see below) you could just add another server.use statement for this Neo4j-based GraphQL endpoint to the example movies.js (note the IP as seen from the client-side and the trailing slash in the URL).

server.use('/neo4j-graphiql', graphiqlExpress({
  // IP is the external Docker host IP as seen by your browser
  endpointURL: 'http://192.168.178.28:7474/graphql/',
  // Note the trailing slash in the URL
  passHeader: 'Authorization: "Basic bmVvNGo...="',
  query: `{
}`,
}));

(Although the movies.js example uses another, extended movie db you can use the default Neo4j Movie DB as Neo4j now is your GraphQL server.)

For the default Neo4j Movie DB the auto-created schema for queries looks like that:
NEO4J-GRAPHQL_QUERYTYPE

And as neo4-graphql already supports basic mutations it also gives you the following mutations:
NEO4J-GRAPHQL_MUTATIONTYPE

Summing up: neo4-graphql is a Neo4j server extension making Neo4j itself the GraphQL API endpoint. It can accept a custom schema or create one from the existing db and it already supports mutations.

neo4-graphql-js

In contrast the NodeJS based neo4j-graphql-js does not support mutations (yet) and is completely external to Neo4j. It is to be used with a stand-alone (e.g. graphql-server-express based) GraphQL server which talks to the Neo4j sever via the js neo4j-driver. As of now you also need to provide your own schema.

However, you do not need to write custom resolvers for each GraphQL operation and you can use a @cypher schema directive to annotate fields with the result of the given cypher query (for that to work you need to add the appropriate APOC procedure library for your version to Neo4j plugins directory):

FROM neo4j:latest

COPY apoc-3.3.0.1-all.jar /var/lib/neo4j/plugins

RUN echo 'dbms.security.procedures.unrestricted=apoc.trigger.*,apoc.meta.*' | tee -a /var/lib/neo4j/conf/neo4j.conf

CMD ["neo4j"]

A basic Dockerfile for the NodeJS container could look like this (the instructions assume that you forked the Github repo and might slightly change if you install it via npm):

FROM node:boron-slim

# context secrets
ENV NEO4J_URI="bolt://<yourNeo4jContainer>:7687"
ENV NEO4J_USER="neo4j"
ENV NEO4J_PASSWORD="<yourNeo4jPassword>" # don't use sensitive ENVs with public/published images

RUN npm install express -g

WORKDIR /path/to/neo4j-graphql-js

# Only on first run after forking the Github repo 
# RUN npm install 

RUN apt-get autoremove -y \
        && apt-get autoclean -y \
        && apt-get clean -y \
        && rm -rf /var/lib/apt/lists/*
        
# 9229 is only for debugging
EXPOSE 3000 9229

USER node

CMD ["npm", "start"]

You then need to create a file which follows the example movies.js with:

  • your own schema (according to your database schema),
  • a config for the Neo4j driver and server statements for the graphql and graphiql endpoints (these can be the same as in the movies.js)
  • Optionally you can also add another neo4j-graphiql endpoint as described above for neo4-graphql (you can then use both within one setup)
  • Optionally (only if you forked the Github repo) change your package.json start script to "nodemon ./example/graphql-tools/<yourFile>.js --exec babel-node -e js --inspect"

After building the images and running the containers you have a full setup for neo4j-graphql and neo4j-graphql-js in only two docker containers for testing/comparing purposes.

Summing up: The neo4-graphql-js is another way to give your Neo4j sever a GraphQL API. It is used in a stand-alone server, completely independent of the Neo4j instance which requires a NodeJS sever. As of now it only supports basic read queries, but no mutations. However, in the long run it might prove more flexible and easier to configure then a prepackaged server extension.

Summary

Both neo4j-graphql and neo4j-graphql-js are still in early development and are about to change. However, already now they offer significant benefits such as especially:

  • Always sending a single query to the database
  • And no need to write queries for each resolver

In fact it was amazing to see how little effort it took in the backend to provide various data to the frontend. And despite the early development stage, some rough edges and bugs it was fun working with it.

Beyond that it pretty quickly became clear/tangible where the advantages of GraphQL over REST are - at least if you combine two technologies which both regard data as a graph and whose operations (on sub-trees within it) thus can easily be translated.

Update: There is also a follow-up blog post now available: Using and Accessing neo4j-graphql with NodeJS

Further Information

GraphQL:
http://graphql.org
http://graphql.org/code/

Neo4j:
https://github.com/neo4j-graphql
https://github.com/neo4j-graphql/neo4j-graphql
https://github.com/neo4j-graphql/neo4j-graphql-js
https://neo4j.com/developer/graphql/

DZone RefCard:
https://dzone.com/refcardz/an-overview-of-graphql

Videos:
https://go.neo4j.com/building-a-graphql-service-backed-by-neo4j-lp.html
https://youtu.be/0EmZjheYv-U

GRANDstack:
http://grandstack.io/

Example Launchpad:
(with the advanced movie db used in movies.js)
https://launchpad.graphql.com/n59x9mw47

Data Modelling Guide:
https://www.graph.cool/docs/reference/database/data-modelling-eiroozae8u/

Using and Accessing neo4j-graphql with NodeJS:
https://daten-und-bass.io/blog/using-and-accessing-neo4j-graphql-with-nodejs/