Neo4j Aura as a Resource Type

Would love for you to support connecting to Neo4j's Aura cloud graph DB as a resource type.

*In full disclosure, I work for Neo4j :slight_smile:

1 Like

Thanks for the request @sfbrophy! Could you shoot me an email at justin@retool.com about this?

big plus 1!

It would be great!!

+1 here!

+1

Circling back here since this came up in office hours. This is a feature request that we are tracking internally. Currently, it's not something we are actively developing, but it is something we could pick up in the future. The suggested workaround is to use a rest query. :slightly_smiling_face: It's always helpful to get more feedback from users that also want this integration or users that can't solve their use case with the workaround.

I finally had to do this myself so I thought I would post this here to help others with the pent-up demand. Since my Aura instance is hosted on the GCP us-central1 I decided to create a Google Cloud Function (there) to translate a REST call to what Aura understands. This turns out to be reasonably easy which makes it all the more incredible that Neo4j and/or Retool doesn't just do this for us. (Everything I describe here should work equally well with AWS Lambda and Azure Functions... in theory...).

First up, Neo4j does publish a Javascript API. It requires Node and so when I created the cloud function (in the console) I specified:

Runtime : Node.js 20

I named my function: Entry point : neo4j_aura_query. So that's not some magic string, just the name I gave my one and only function.

BTW the Google Cloud console is pretty complicated and I'm no expert so you will not be able to just follow these instructions easily. I followed "serverless" to "app engine" to "cloud functions".

Setting up an authorization method for your Retool app to call your cloud function is quite complex. I won't even try to explain that.

The Neo4j documentation on their official Javascript API is here:

To add the library to package.json; I had to do this:

{
  "name": "neo4j-cloud-function",
  "version": "1.0.0",
  "dependencies": {
    "@google-cloud/functions-framework": "^3.0.0",
    "neo4j-driver": "^4.3.7"
  }
}

Because "@google-cloud/functions-framework": "^3.0.0" is also required (it was there by default). All I did was add "neo4j-driver": "^4.3.7".

Also using the GCP console, I created "Runtime environment variables" to hold the magic bolt-style URI (neo4j+s://foo.databases.neo4j.io:7687) of my Neo4j Aura database, and the basic auth username and password required by Aura.

Neo4j publishes a sample bit of JavaScript which is this simple:

var neo4j = require('neo4j-driver');

const URI = process.env.neo4j_uri;
const USER = process.env.neo4j_user;
const PASSWORD = process.env.neo4j_password;

exports.neo4j_aura_query = async (req, res) => {
  if (req.method !== 'POST') {
    res.status(405).send('Method Not Allowed');
    return;
  }

  let driver;

  try {
    driver = neo4j.driver(URI, neo4j.auth.basic(USER, PASSWORD),{"disableLosslessIntegers":true});
    const session = driver.session();
    const result = await session.run(req.body);
    res.status(200).send(result.records);

  } catch (err) {
    res.status(500).send(`Connection error\n${err}\nCause: ${err.cause}`);
  } finally {
    await driver.close();
  }
};

This bit:

const URI = process.env.neo4j_uri;
const USER = process.env.neo4j_user;
const PASSWORD = process.env.neo4j_password;

Is linking this code to the Google Cloud Functions environment variables mentioned above.
There is one other change I made here:

driver = neo4j.driver(URI, neo4j.auth.basic(USER, PASSWORD),{"disableLosslessIntegers":true});

The third argument: {"disableLosslessIntegers":true} is not part of the boilerplate. The need for this (or not) is discussed here:

https://neo4j.com/docs/api/javascript-driver/current/class/lib6/types.js~Config.html#instance-member-disableLosslessIntegers

And here: https://stackoverflow.com/q/42645342

TLDR;

My database has small real numbers like 0.25, 1.0, 1.25, etc. and the default behavior of the Neo4j driver is to return a JSON structure like this: {low: 1, high: 0}. Even though all this discussion talks about integers, it applies to real numbers as well. Neo4j's native representation of numbers is > than the range Javascript supports so this is their solution. If your data will comfortably work with Javascript native math then disableLosslessIntegers:true will return something Javascript can consume without special handling.

Having setup the above and gone through the deploy process your cloud function will establish a REST API at a URL like https://us-central1-fooincorporated.cloudfunctions.net/neo4j-aura-query.

You can now go to Retool and setup a REST API consumer like this:

NOTE: There is no authorization header in the above screenshot. Like I said...it's complicated...

When you have finished debugging auth and finally execute it, you will get back data in a style of JSON defined by Neo4j:

Since the body of the query is the plain text of a Cypher query you can do inserts/updates/etc. with just this one API.

One more gotcha. Google Cloud Functions has parameters for how many functions can be activated simultaneously, how many can be stacked up on one "machine" (I think a "container"), how much memory they can consume, CPU, etc. and how long they are allowed to run before Google kills them. The default is 60 seconds and I had to increase that as some of my Cypher queries took a bit longer. For all the other values the (very minimal) defaults have been fine so far.

1 Like

Thanks so much for sharing!!

Hi @Tess and @justin , any updates on progress for a Neo4j AuraDB resource type? :blush:

No updates yet, @AdamT :disappointed: I'll add your +1