Installation

The OGM can be installed into a new or existing Node.js project in a similar way to the installation of the Neo4j GraphQL Library. As such, it requires some dependencies to be included:

  • @neo4j/graphql-ogm: the OGM package.

  • graphql: the package used by the Neo4j GraphQL Library to generate a schema and execute queries and mutations.

  • neo4j-driver: the official Neo4j Driver package for JavaScript, necessary for interacting with the database.

npm install @neo4j/graphql-ogm graphql neo4j-driver

To use the OGM, you must always import it:

const { OGM } = require("@neo4j/graphql-ogm");

Usage examples

Here are some examples of how you might take advantage of the OGM.

Custom Resolvers

A common case for using the OGM will be within custom resolvers inside a Neo4j GraphQL instance (very meta!), due to the fact that it has access to some fields which the Neo4j GraphQL Library may not. A common use case might be to have a password field marked with directive @private, and a custom resolver for creating users with passwords.

To get started with this example, create your example application directory, create a new project and also the file which will contain your application code:

mkdir ogm-custom-resolvers-example
cd ogm-custom-resolvers-example
npm init --yes
touch index.js

Then you need to install your dependencies:

npm install @neo4j/graphql-ogm graphql neo4j-driver apollo-server

Assuming a running Neo4j database at "bolt://localhost:7687" with username "neo4j" and password "password", in your empty index.js file, add the following code:

import { Neo4jGraphQL } from "@neo4j/graphql";
import { OGM } from "@neo4j/graphql-ogm";
import { Neo4jGraphQLAuthJWTPlugin } from "@neo4j/graphql-plugin-auth";
import { ApolloServer } from "apollo-server";
import neo4j from "neo4j-driver";

import { createJWT, comparePassword } from "./utils"; // example util function, more information below

const driver = neo4j.driver(
    "bolt://localhost:7687",
    neo4j.auth.basic("username", "password")
);

const typeDefs = `#graphql
    type User {
        id: ID @id
        username: String!
        password: String! @private
    }

    type Mutation {
        signUp(username: String!, password: String!): String! ### JWT
        signIn(username: String!, password: String!): String! ### JWT
    }
`;

const ogm = new OGM({ typeDefs, driver });
const User = ogm.model("User");

const resolvers = {
    Mutation: {
        signUp: async (_source, { username, password }) => {
            const [existing] = await User.find({
                where: {
                    username,
                },
            });

            if (existing) {
                throw new Error(`User with username ${username} already exists!`);
            }

            const { users } = await User.create({
                input: [
                    {
                        username,
                        password,
                    }
                ]
            });

            return createJWT({ sub: users[0].id });
        },
        signIn: async (_source, { username, password }) => {
            const [user] = await User.find({
                where: {
                    username,
                },
            });

            if (!user) {
                throw new Error(`User with username ${username} not found!`);
            }

            const correctPassword = await comparePassword(password, user.password);

            if (!correctPassword) {
                throw new Error(`Incorrect password for user with username ${username}!`);
            }

            return createJWT({ sub: user.id });
        },
    },
};

const neoSchema = new Neo4jGraphQL({
    typeDefs,
    driver,
    resolvers,
    plugins: {
        auth: new Neo4jGraphQLAuthJWTPlugin({
            secret: "secret"
        })
    }
});

Promise.all([neoSchema.getSchema(), ogm.init()]).then(([schema]) => {
    const server = new ApolloServer({
        schema,
    });

    startStandaloneServer(server, {
        context: async ({ req }) => ({ req }),
    }).then(({ url }) =>  {
        console.log(`🚀 Server ready at ${url}`);
    });
});

It’s important to note the JWT secret being passed into the Neo4jGraphQL constructor in this example.

Additionally, an example implementation for the util functions createJWT and comparePassword is provided in this code snippet:

const jwt = require("jsonwebtoken");
const bcrypt = require("bcrypt");

export function createJWT(data) {
    return new Promise((resolve, reject) => {
        jwt.sign(data, "<insert your JWT secret here!>", (err, token) => {
            if (err) {
                return reject(err);
            }

            return resolve(token as string);
        });
    });
}

export function comparePassword(plainText, hash) {
    return new Promise((resolve, reject) => {
        bcrypt.compare(plainText, hash, (err, result) => {
            if (err) {
                return reject(err);
            }

            return resolve(result);
        });
    });
}

This code for the util functions createJWT and comparePassword is an example. You will likely need to adjust it to suit your use case.

Back in the command line, run the following command to start your server:

node index.js

You should see the following output:

🚀 Server ready at http://localhost:4000/

You can execute the signUp Mutation against this GraphQL API to sign up, but when you go to query the user through the same API, the password field will not be available.

REST API

This example demonstrates how you might use the OGM without exposing a Neo4j GraphQL API endpoint. The example starts an Express server and uses the OGM to interact with the Neo4j GraphQL Library, exposed over a REST endpoint.

First, create your example application directory, create a new project and also the file which will contain yur application code:

mkdir ogm-rest-example
cd ogm-rest-example
npm init --yes
touch index.js

Then you need to install your dependencies:

npm install @neo4j/graphql-ogm graphql neo4j-driver express

Assuming a running Neo4j database at "bolt://localhost:7687" with username "neo4j" and password "password", in your empty index.js file, add the following code:

const express = require("express");
const { OGM } = require("@neo4j/graphql-ogm");
const neo4j = require("neo4j-driver");

const driver = neo4j.driver(
    "bolt://localhost:7687",
    neo4j.auth.basic("username", "password")
);

const typeDefs = `
    type User {
        id: ID
        name: String
    }
`;

const ogm = new OGM({ typeDefs, driver });
const User = ogm.model("User");

const app = express();

app.get("/users", async (req, res) => {
    const { search, offset, limit, sort } = req.query;

    const regex = search ? `(?i).*${search}.*` : null;

    const users = await User.find({
        where: { name_REGEX: regex },
        options: {
            offset,
            limit,
            sort
        }
    });

    return res.json(users).end();
});

const port = 4000;

ogm.init().then(() => {
    app.listen(port, () => {
        console.log("Example app listening at http://localhost:${port}")
    });
});

In your application directory, you can run this application:

node index.js

Which should output:

Example app listening at http://localhost:4000

The REST API should now be ready to accept requests at the URL logged.