Overview About GraphQL GraphQL Queries GraphQL as a Contract Schema The GRANDstack Java Extension: neo4j-graphql JavaScript Implementation: neo4j-graphql-js GraphQL Support Raw Data Access Resources About GraphQL GraphQL is a specification for querying a slice of an application graph, retrieving a… Read 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 where that data was pulled from. It covers tree-based read queries, mutations for updates, and subscriptions for live updates.

GraphQL Queries

Queries in GraphQL 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

At a high level, GraphQL builds 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 either piece independently while the type system stays consistent. Each query from the front-end is using that type system to precisely define which data it is interested in.

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

GraphQL queries return data in a tree form that perfectly matches the frontend view hierarchy. If the application data is a graph, then the perfect backend is a graph database with native support for resolving GraphQL queries – Neo4j.

Schema

The type system is often declared in schema (IDL) files which contain entities, their attributes, interfaces, and enumerations, as well as 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]
}

The GRANDstack

GRANDstack is a full-stack development integration for building graph-based applications.

GRAND stands for the following technologies:

  • 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 – a graph database that is ACID-compliant and built to store and retrieve connected data

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

Java Extension: neo4j-graphql

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 are able to generate a single query against the backing graph database. During development, both Neo4j’s property graph model and the Cypher query language turned out to be great fits for the GraphQL features supported so far.

You can grab the latest release of 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 by posting an IDL file with your preferred schema.

We added some neat features that we hope are useful and make your life easier. We are 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 of how the schema definition above could or 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 comes “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 use some of those features.

JavaScript Implementation: neo4j-graphql-js

We have 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 will 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.

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).