Reputation: 69
I'm currently using Aws Appsync, Aws Lambda, and Aws Neptune for an application. My Lambda function uses NodeJS 12. Right now my problem is getting back the appropriate JSON format from Neptune (more specifically gremlin) for my graphql api (appsync) when I do a mutation and eventually a query (I want to make sure the mutations are working first). For example:
When I run this test query to add a post, I get the following error with data being null: addPost test query and result
Does adding a vertex in gremlin return data/an object? If so, how do I get the appropriate JSON format for my appsync graphql api? I've been reading Practical Gremlin and searching the web but no luck. Thank you in advance.
Upvotes: 5
Views: 1631
Reputation: 2769
More than likely what you're seeing is related to an incompatibility in Lambda with the default return format for the Node.js GLV. The default format returned is GraphSONV3, which is JSON-like but not well-formatted JSON. Lambda is expecting well-formatted JSON. You can change the mimetype when establishing your connection to Neptune to use GraphSONV2 which Lambda shouldn't have any issues with.
const dc = new DriverRemoteConnection(
`wss://<neptune-endpoint>:8182/gremlin`,
{ mimeType: "application/vnd.gremlin-v2.0+json" }
);
The other thing to validate is how you are resolving the promise being returned by the await'd Gremlin query. It looks like in your sample code that you are taking the result of the await'd query and feeding that into JSON.stringify(). I don't think that will work, as that will effectively return the JSON stringified version of the Promise (which is what you're seeing). What you can do in this case (if you want to submit queries asynchronously) is to take your Gremlin queries (or maybe even this larger case statement) and put it into an async function outside of the Lambda handler. Example:
const gremlin = require('gremlin');
const DriverRemoteConnection = gremlin.driver.DriverRemoteConnection;
const Graph = gremlin.structure.Graph;
const dc = new DriverRemoteConnection('wss://<neptune-endpoint>:8182/gremlin',
{ mimeType: "application/vnd.gremlin-v2.0+json" }
);
const graph = new Graph();
const g = graph.traversal().withRemote(dc);
async function callNeptune() {
const result = await g.addV('Post').property('userId','someid').
property('genre','somegenre').
property('caption','somecaption').
property('timestamp','sometimestamp').
toList();
console.log(result);
dc.close();
try {
return result;
} catch (error) {
return error;
}
}
exports.handler = async (event) => {
const rawOutput = await callNeptune();
const jsonOutput = JSON.stringify(rawOutput);
const response = {
statusCode: 200,
body: jsonOutput,
};
return response;
};
In this scenario, you're await'ing the async function with your Gremlin query via an await call that is now in the handler. So you can then take the results from that and feed it into JSON.Stringify() and return it. The Lambda service will resolve the promise of the handler at that point.
FWIW, there's little benefit to using async/await from a Lambda-backed API layer to Neptune. Both the Lambda function and the Neptune server side threads will be waiting (and holding up resources) until all of the promises are resolved. In many cases this can just add complexity over just using synchronous calls. It would be different if you were doing this from a long-running containerized application or from a web-based front end, where letting other processes in the meantime makes sense.
Upvotes: 3