Installation

You can install the OGM into a new or existing Node.js project in a similar way to how you install the Neo4j GraphQL Library. It has the following dependencies:

  • @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

Usage examples

Here are some examples of how you can use the OGM.

Custom Resolvers

The OGM has access to some fields which the Neo4j GraphQL Library doesn’t. It is common practice to use the OGM to create custom resolvers when dealing with such fields. For example, you can have a password field marked with the @private directive and a custom resolver for creating users with passwords.

Execute the following to create an example application directory and create a new project:

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

Install the dependencies:

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

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

import { ApolloServer } from "@apollo/server";
import { startStandaloneServer } from "@apollo/server/standalone";
import { Neo4jGraphQL } from "@neo4j/graphql";
import { OGM } from "@neo4j/graphql-ogm";
import neo4j from "neo4j-driver";

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

const driver = neo4j.driver(
    "neo4j://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,
    features: {
        authorization: {
            key: "secret",
        },
    },
});

async function main() {
    await ogm.init();

    const server = new ApolloServer({
        schema: await neoSchema.getSchema(),
    });

    const { url } = await startStandaloneServer(server, {
        listen: { port: 4000 },
        context: async ({ req }) => ({
            token: req.headers.authorization,
        }),
    });

    console.log(`🚀 Server ready at ${url}`);
}

main();

Create the file utils.js in the same directory. Install additional dependencies:

npm install bcrypt jsonwebtoken

Add the following code to utils.js:

import bcrypt from "bcrypt";
import jwt from "jsonwebtoken";

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);
        });
    });
}

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

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

The code for the util functions createJWT and comparePassword is an example. Adjust it to suit your use case.

Back on 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 the GraphQL API to sign up, but if you try querying the user through the same API, the password field will not be available.

REST API

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

Execute the following to create an example application directory and a new project:

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

Install the dependencies:

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

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

import express from "express";
import { OGM } from "@neo4j/graphql-ogm";
import neo4j from "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,
  features: { filters: { String: { MATCHES: true } } },
});

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_MATCHES: 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}/users`);
  });
});

In your application directory, you can run this application:

node index.js

You should see the following output:

Example app listening at http://localhost:4000/users

The REST API should now be available at http://localhost:4000, with a single working route /users.