Overview About GraphQL Queries GraphQL as a Contract Schema GraphQL and Neo4j GRANDstack Neo4j GraphQL extension neo4j-graphql-js GraphQL Support Resources Raw Data Access About GraphQL GraphQL is a specification for querying a slice of an application graph, retrieving a tree… Learn More →

About GraphQL

200px GraphQL Logo.svg

GraphQL is a specification for querying a slice of an application graph, retrieving a tree of data that perfectly matches a front-end view, regardless of was that data was pulled from. It covers tree-based read-queries, mutations for updates and subscriptions for live updates.

Queries

Queries form a tree structure, based upon entities and relevant attributes. Any of those can take parameters (e.g for filtering or pagination) and directives.

GraphQL example query
query {
   Movie(title:"The Matrix") {
      title
      released
      tagline
      actors {
         name
         born
      }
   }
}
GraphQL example result
{
   "Movie": [{
      "title": "The Matrix",
      "released": 1999,
      "tagline": "Welcome to the Real World",
      "actors": [{
         "name": "Keanu Reeves",
         "born": 1964
         }, {
         "name": "Carrie-Anne Moss",
         "born": 1967
         }, {
         "name": "Laurence Fishburne",
         "born": 1961
         }
      ]
   }]
}

GraphQL as a Contract

In this regard it is a contract between front-end and back-end, based on the agreed upon type system which forms an application data model in the form of a graph.

It decouples the front-end from the back-end data source(s), which allows you to change both independently as the type system stays consistent. Each query from the front-end is using that type system to define in a fine grained way which data it is interested in.

There is no prescription how and where the data in the back-end comes from, it can be anything from databases, to APIs, from third party systems to in-memory representations, and even code or static assets.

GraphQL queries return data in a tree-form that perfectly matches the front end view hierarchy. If the application data is a graph, then the perfect back-end is a Graph Database with native support for resolving GraphQL queries: Neo4j.

Schema

The typesystem is often declared in schema (IDL) files which contain entities, their attributes, interfaces, enumerations, but also mutations and subscriptions. The schema can be extended with custom directives and types that allow specific extensions of the core language.

GraphQL example schema
type Movie {
    title: String!
    released: Int
    tagline: String
    actors: [Person]
}

type Person {
    name: String!
    born: Int
    movies: [Movie]
}

GraphQL and Neo4j

GRANDstack

GRANDstack is a stack for building GraphQL/Neo4j backed applications. GRAND stands for:

  • GraphQL – A query language for APIs and a runtime for fulfilling those queries with your existing data.
  • React – A JavaScript library for building user interfaces
  • Apollo Client – A fully-featured, production ready caching GraphQL client for every server or UI framework
  • Neo4j Database

Will Lyon facilitated a training session at GraphConnect NYC 2017 in which attendees built their first GRANDstack application.

Neo4j GraphQL extension

neo4j graphql logo

We wanted to combine the power of Neo4j and GraphQL by making it super-easy to take an IDL schema OR an existing graph and serve a native GraphQL backend from it.

With the information from the schema we’re able to generate a single query against the backing graph database. During development both Neo4j’s property graph model as well as the Cypher query language turned out to be a great fit for the GraphQL features we’re supporting so far.

You can grab the latest release our extension from here and drop it into any Neo4j 3.1.x server (in the plugins directory). After a restart you can either query your graph data using GraphQL directly or after posting an IDL file with the schema you like.

We added some neat features that we hope are useful and make your life easier.

We’re especially proud of the @cypher directive, the auto-generated mutations (create, update, delete), and the graphql.execute, graphql.idl and graphql.schema procedures.

Here is an example, how the schema definition above could / would be extended:

type Movie {
    title: ID!
    released: Int
    tagline: String

    actors: [Person] @relation(name:"ACTED_IN", direction:IN)

    director: Person @relation(name:"DIRECTED", direction:IN)

    recommendation(first:Int = 3): [Movie]
      @cypher(statement:"MATCH (this)<-[r1:REVIEWED]-(:User)-[r2:REVIEWED]->(reco:Movie)
                         WHERE 3 <= r1.stars <= r2.stars
                         RETURN reco, sum(r2.stars) as rating ORDER BY rating DESC")
}

interface Person {
    name: ID!
    born: Int
}

type Actor extends Person {
    name: ID!
    born: Int

    movies: [Movie] @relation(name:"ACTED_IN")
}

type Director extends Person {
    name: ID!
    born: Int

    movies: [Movie] @relation(name:"DIRECTED")
}

type Mutations {
    directed(movie:ID! director:ID!) : String
      @cypher(statement:"MATCH (m:Movie {title: $movie}), (d:Person {name: $director})
                         MERGE (d)-[:DIRECTED]->(m)")
}
schema {
   mutations: Mutations
}

Have a look at the following “feature” table, to see what else is “in the box”:

name information example

entities

each node label represented as entity

{ Person {name,born} }

multi entities

multiple entities per query turned into UNION

{ Person {name,born} Movie {title,released} }

properties (out)

via sampling property names and types are determined

{ Movie {title, released} }

field parameters

all properties can be used as filtering (exact/list) input parameters, will be turned into Cypher parameters

{ Movie(title:"The Matrix") {name,released} }

query parameters

passed through as Cypher parameters

query MovieByParameter ($title: String!) { Person(name:$name) {name,born} }

relationships

via a @relationship annotated field, optional direction

type Person { name: String, movies : Movie @relation(name:"ACTED_IN", direction:OUT) }

ordering

via an extra orderBy parameter

query PersonSortQuery { Person(orderBy:[name_desc,born_desc]) {name,born}}

pagination

via first and offset parameters

query PagedPeople { Person(first:10, offset:20) {name,born}}

schema first IDL support

define schema via IDL

:POST /graphql/idl "type Person {name: String!, born: Int}"

Mutations

create/delete mutations inferred from the schema

createMovie(title:ID!, released:Int) updateMovie(title:ID!, released:Int) deleteMovie(title:ID!)

createMoviePersons(title:ID!,persons:[ID!]) deleteMoviePersons(title:ID!,persons:[ID!])

Cypher queries

@cypher directive on fields and types, parameter support

actors : Int @cypher(statement:"RETURN sizethis)←[:ACTED_IN]-(")

Cypher updates

Custom mutations by executing @cypher directives

createPerson(name: String) : Person @cypher(statement:"CREATE (p:Person {name:{name}}) RETURN p")

extensions

extra information returned

fields are: columns, query, warnings, plan, type READ_ONLY/READ_WRITE,

@cypher directives can have a passThrough:true argument, that gives sole responsibility for the nested query result for this field to your Cypher query. You will have to provide all data/structure required by client queries. Otherwise, we assume if you return object-types that you will return the appropriate nodes from your statement.

In the repository, you can find a movies schema and accompanying queries, that uses some of those features.

neo4j-graphql-js

We’ve also created the neo4j-graphql-js npm package, which makes it easier to use GraphQL and Neo4j together.

neo4j-graphql-js translates GraphQL queries to a single Cypher query, eliminating the need to write queries in GraphQL resolvers and for batching queries. It also exposes the Cypher query language through GraphQL via the @cypher schema directive.

GraphQL Support

To demonstrate the combined power of a graph database (Neo4j) and GraphQL we also added the GraphQL extension to this server. Access the GraphQL community graph, including GraphiQL here.

After authorising you’ll be able to query the GraphQL community graph with your trusted tools like GraphiQL or Apollo-Client. You can also visualize the Schema using Voyager.

graphql community query leeb

graphql community voyager

You can find the schema for the data and several GraphQL queries and screenshots of your tools in action in this repository.

Resources

If you want to provide more feedback, just create an issue in any of our neo4j-graphql repositories, drop us an email or join neo4j-users Slack and ask in the #neo4j-graphql channel.

Raw Data Access

The raw graph data is publicly accessible here via the Neo4j Browser (http://107.170.69.23:7474 username/pwd: graphql/graphql).

community graphql cypher graph

community.graphql.cypher.table

If you are used to Neo4j you can use it right away by writing some Cypher statements. Here are (some suggestions).