Neo4j GraphQL Server
  • Introduction
  • Neo4j GraphQL Server
  • Neo4j GraphQL Binding
    • neo4jGraphQLBinding
    • neo4jIDL
    • neo4jAssertConstraints
    • buildNeo4jTypeDefs
    • buildNeo4jResolvers
  • GRANDstack Starter
  • GraphQL Community Graph
Powered by GitBook
On this page
  • Installation
  • Strategy
  • Quick Start
  • Nested Mutation
  • Query
  • More Examples
  • Using @cypher Directives
  • Using Multiple Bindings
  • Prism Graph
  • API Reference

Neo4j GraphQL Server

A quick way to get started using neo4j-graphql-binding with Apollo Server.

PreviousIntroductionNextNeo4j GraphQL Binding

Last updated 6 years ago

Installation

npm install -s neo4j-graphql-server

Strategy

This package uses with to make it easier to get started using a generated API or setting up multiple bindings.

The following describes the server setup process based on the default configuration:

  1. Finally, steps 1-5 are processed for any additional binding configurations provided in bindings and the resulting typeDefs and resolvers are merged and provided to Apollo Server.

Quick Start

This example server setup uses only auto-generated query and mutation types.

typeDefs

const typeDefs = `
  type Technology @model {
    name: String! @unique
    integration: [Technology] @relation(
      name: "HAPPINESS", 
      direction: OUT
    )
  }
`;

Server

import { Neo4jGraphQLServer } from 'neo4j-graphql-server';
import { v1 as neo4j } from 'neo4j-driver';

const driver = neo4j.driver(
  process.env.NEO4J_URI || "bolt://localhost:7687",
  neo4j.auth.basic(
    process.env.NEO4J_USER || "neo4j",
    process.env.NEO4J_PASSWORD || "neo4j"
  )
);

const server = Neo4jGraphQLServer({
  typeDefs: typeDefs,
  driver: driver
});

server.listen().then( ({ url }) => {
  console.log(`🚀 Server ready at ${url}`);
});

Nested Mutation

Request

 mutation {
  createTechnology(
    data: {
      name: "Apollo",
      integration: {
        create: [
          {
            name: "GraphQL",
            integration: {
              create: [
                {
                  name: "Neo4j",
                  integration: {
                    connect: [
                      {
                        name: "Apollo"
                      }
                    ]
                  }
                }
              ]
            }
          }
        ]
      }
    }
  ) {
    id        
    name
    integration {
      id
      name
      integration {
        id
        name
        integration {
          id
          name
        }
      }
    }
  }
}

Response

{
  "data": {
    "createTechnology": {
      "id": "cjj0dr5i00006fgr0tfukv1tn",
      "name": "Neo4j",
      "integration": [
        {
          "id": "cjj0dr5i00007fgr05js3fg30",
          "name": "GraphQL",
          "integration": [
            {
              "id": "cjj0dr5i00008fgr06ugrjnze",
              "name": "Apollo",
              "integration": [
                {
                  "id": "cjj0dr5i00006fgr0tfukv1tn",
                  "name": "Neo4j"
                }
              ]
            }
          ]
        }
      ]
    }
  }
}

Query

Now we can run the following query:

Request

query {
  Technology(orderBy: name_desc) {
    id
    name
  }
}

Response

{
  "data": {
    "Technology": [
      {
        "id": "cjj0dr5i00006fgr0tfukv1tn",
        "name": "Neo4j"
      },
      {
        "id": "cjj0dr5i00007fgr05js3fg30",
        "name": "GraphQL"
      },
      {
        "id": "cjj0dr5i00008fgr06ugrjnze",
        "name": "Apollo"
      }
    ]
  }
}

More Examples

Using @cypher Directives

The below typeDefs shows the use of the @cypher directive for a computed field, a query, and a mutation type. Any query and mutation types, or resolvers, that you provide are not overwritten by the schema augmenting process.

typeDefs

type Movie @model {
  title: String!
  released: Int
  actors: [Person] @relation(name:"ACTED_IN",direction:IN)
  # computed field
  directors: [Person] @cypher(statement: """
    MATCH (this)<-[:DIRECTED]-(d) RETURN d
  """)
}
type Person @model {
  name: String!
  born: Int
  movies: [Movie] @relation(name:"ACTED_IN")
}
type Query {
  coActors(name:ID!): [Person] @cypher(statement:"""
    MATCH (p:Person {name:$name})-[:ACTED_IN]->()<-[:ACTED_IN]-(co) 
    RETURN distinct co
  """)
}
type Mutation {
  rateMovie(user:ID!, movie:ID!, rating:Int!): Int @cypher(statement: """
    MATCH (p:Person {name:$user}),(m:Movie {title:$movie}) 
    MERGE (p)-[r:RATED]->(m) SET r.rating=$rating 
    RETURN r.rating
  """)
}
schema {
   query: Query
   mutation: Mutation
}

The corresponding resolvers can be provided if you want to handle the data or be explicit. Otherwise, they will be generated.

Query: {
  coActors: (obj, params, ctx, info) => {
    return ctx.neo4j.query.coActors(params, info);
  }
  // Movie (generated)
  // Person
},
Mutation: {
  rateMovie: async (obj, params, ctx, info) => {
    const result = await ctx.neo4j.mutation.rateMovie(params, info);
    // using result
    return result;
  }
  // createMovie (generated)
  // createPerson
}

Using Multiple Bindings

Prism Graph

mutation {
  createTechnology(
    data: {
      name: "A",
      integration: {
        create: [
          {
            name: "B",
            integration: {
              connect: {
                name: "D"
              }
            }
          },
          {
            name: "C",
            integration: {
              create: [
                {
                  name: "E",
                  integration: {
                    connect: [
                      {
                        name: "F"
                      },
                      {
                        name: "B"
                      }
                    ]
                  }
                },
                {
                  name: "F",
                  integration: {
                    connect: {
                      name: "D"
                    }
                  }
                }
              ]
            }
          },
          {
            name: "D"
          }
        ]
      }
    }) {
    id        
    name
    integration {
      id
      name
      integration {
        id
        name
        integration {
          id
          name
        }
      }
    }
  }
}

API Reference

All the same arguments as Apollo Server are supported, in addition to the following:

  • typeDefs (required): Your GraphQL type definitions in SDL format

  • calls Configures the use of neo4jAssertConstraints and neo4jIDL during setup.

    • assert (default: true): A boolean control that updates the unique property constraints in your Neo4j instance.

    • idl (default: true): A boolean control that updates your Neo4j-GraphQL schema.

  • augment Configures the use of buildNeo4jTypeDefs and buildNeo4jResolversduring setup.

    • typeDefs

      • query (default: true) A boolean controlling the generation of query types.

      • mutation (default: true) A boolean controlling the generation of mutation types.

    • resolvers

      • query (default: true) A boolean controlling the generation of resolvers for query types.

      • mutation (default: true) A boolean controlling the generation of resolvers for mutation types.

  • indexConfig Configures the management of generated id fields.

    • use (default/only: 'cuid') Configures what method to use when generating id field values.

  • bindingKey (default: 'neo4j'): The key used when storing the created binding into the server's context object.

  • log (default: false): Logs the result of any delegated query or mutation operation, buildNeo4jTypeDefs,neo4jAssertConstraints, and neo4jIDL.

  • readOnly (default: false): If you only have read access to a remote server, then you can use this parameter to turn off all processes that assume write access. Mutation types are not generated, idl and assert calls are prevented, and id fields are not generated and managed because we would never be able to write them to the instance. So, this results in forcing the following configuration:

calls: { 
  idl: false,
  assert: false
},
augment: {
  mutation: false
},
indexConfig: false
  • bindings An object of bindings where each key is the name for a binding and each value is a configuration object containing the parameters: typeDefs, resolvers, driver, calls, augment, log, and readOnly. This can be used to network together a GraphQL binding for multiple remote Neo4j instances with the Neo4j-GraphQL extension installed.

Default Configuration

Neo4jGraphQLServer({
  typeDefs: typeDefs,
  resolvers: resolvers,
  driver: driver,
  calls: {
    assert: true, 
    idl: true
  },
  augment: {
    typeDefs: {
      query: true,
      mutation: true
    },
    resolvers: {
      query: true, 
      mutation: true
    }
  },
  indexConfig: {
    use: "cuid"
  },
  bindingKey: 'neo4j',
  log: true,
  readOnly: false,
  bindings: {
    ...
  }
});

is called to update your Neo4j-GraphQL schema.

is used to support a @unique directive by in your Neo4j instance. It uses the .

then augments the same typeDefs provided to your Neo4j-GraphQL schema.

is used to create a over the resulting augmented typeDefs. The binding is added into your server's (default key: 'neo4j' so you can access it the way you normally would access a GraphQL Binding.

then generates any unprovided resolvers for query and mutation types that were generated or that use a . Each resolver uses a created binding to delegate all such queries and mutations to a Neo4j-GraphQL endpoint.

If you navigate to , you should see .

This example uses nested mutations and takes advantage of the directive to create the above graph with three Technology nodes.

See the section on for an example of configuring bindings for multiple local or remote Neo4j instances with the Neo4j-GraphQL extension available.

This mutation creates a ! 🌈

driver(required): Your Neo4j driver instance (More info ).

neo4jIDL
neo4jAssertConstraints
creating constraints
APOC extension
buildNeo4jTypeDefs
neo4jGraphQLBinding
custom GraphQL Binding
context parameter
buildNeo4jResolvers
@cypher directive
http://localhost:4000/
GraphQL Playground
create and connect
@unique
using the GraphQL Community Graph
Prism Graph
here
neo4j-graphql-binding
Apollo Server
Create this graph in the Quick Start below! (image from Neo4j Bloom)
Prism Graph in Neo4j Bloom