Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using AWS Appsync with AWS Neptune

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:

  1. Here is my type Post for my graphql schema with addPost mutation right above it: Post schema
  2. The addPost mutation maps to this resolver: Post Mutation Resolver
  3. Which then runs this piece of code: Lambda Code

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.

like image 619
MCam Avatar asked Apr 16 '20 21:04

MCam


People also ask

Does AWS Neptune support GraphQL?

AWS AppSync makes it easy to develop GraphQL APIs, which provides an access layer to the data and builds a flexible backend using AWS Lambda to connect to Neptune.

Does AWS AppSync use API gateway?

What is AWS AppSync? AppSync is a serverless GraphQL service. In simple terms, it's just an API gateway based on the GraphQL specification you can pay on-demand. GraphQL offers a friendly query language on top of HTTP, making it possible to fetch multiple different resources in one request, lowering network latency.

Can AppSync call API gateway?

And thanks to AWS signatures this can happen in a secure way: AppSync can call the API as it can use an IAM Role with the necessary permissions, but for the public it's not available. In this article, we'll see how to configure AppSync to send a signed request to an API Gateway HTTP API using the HTTP data source.

Does Amazon Neptune supports SQL queries?

SQL queries for highly connected data are complex and hard to tune for performance. Instead, Amazon Neptune allows you to use the popular graph query languages Apache TinkerPop Gremlin and W3C's SPARQL and openCypher to execute powerful queries that are easy to write and perform well on connected data.


1 Answers

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.

like image 120
Taylor Riggan Avatar answered Oct 03 '22 06:10

Taylor Riggan