adam_cowley
Neo4j
Neo4j

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 each node label represented as entity { Person {name,born} } multiple entities per query turned into UNION { Person {name,born} Movie {title,released} } via sampling property names and types are determined { Movie {title, released} } all properties can be used as filtering (exact/list) input parameters, will be turned into Cypher parameters { Movie(title:"The Matrix") {name,released} } passed through as Cypher parameters query MovieByParameter ($title: String!) { Person(name:$name) {name,born} } via a @relationship annotated field, optional direction type Person { name: String, movies : Movie @relation(name:"ACTED_IN", direction:OUT) } via an extra orderBy parameter query PersonSortQuery { Person(orderBy:[name_desc,born_desc]) {name,born}} via first and offset parameters query PagedPeople { Person(first:10, offset:20) {name,born}} :POST /graphql/idl "type Person {name: String!, born: Int}" 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 directive on fields and types, parameter support actors : Int @cypher(statement:"RETURN sizethis)←[:ACTED_IN]-(") Custom mutations by executing @cypher directives createPerson(name: String) : Person @cypher(statement:"CREATE (p:Person {name:{name}}) RETURN p") 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.

This is a companion discussion topic for the original entry at https://neo4j.com/developer/graphql/