Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 67f07cf

Browse files
authoredMar 21, 2025··
Changed code to upload schema onto lambda, made resolver template take in schema file as separate file instead of input, made template static by not accepting any input including the timestamp. Also updated integration tests to succeed with these changes (#79)
1 parent 98f9006 commit 67f07cf

File tree

18 files changed

+138
-10650
lines changed

18 files changed

+138
-10650
lines changed
 

‎doc/todoExample.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Let's now run this schema through the utility and create the GraphQL API in AWS
2121

2222
`neptune-for-graphql --input-schema-file ./samples/todo.schema.graphql --create-update-aws-pipeline --create-update-aws-pipeline-name TodoExample --create-update-aws-pipeline-neptune-endpoint` <*your-neptune-database-endpoint:port*> ` --output-resolver-query-https`
2323

24-
Te utility created a new file in the *output* folder called *TodoExample.source.graphql*, and the GraphQL API in AppSync. As you can see below, the utility inferenced:
24+
The utility created a new file in the *output* folder called *TodoExample.source.graphql*, and the GraphQL API in AppSync. As you can see below, the utility inferenced:
2525

2626
- In the type *Todo* it added *@relationship* for a new type *CommentEdge*. This is instructing the resolver to connect *Todo* to *Comment* using a graph database edge called *CommentEdge*.
2727
- A new input called *TodoInput* was added to help the queries and the mutations.

‎package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
"neptune-for-graphql.mjs",
4242
"./templates/CDKTemplate.js",
4343
"./templates/queryHttpNeptune.mjs",
44-
"./templates/JSResolverOCHTTPSTemplate.js",
44+
"./templates/JSResolverOCHTTPS.js",
4545
"./templates/Lambda4AppSyncHTTP/index.mjs",
4646
"./templates/Lambda4AppSyncHTTP/package.json",
4747
"./templates/Lambda4AppSyncSDK/index.mjs",

‎src/main.js

+39-4
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import { graphDBInferenceSchema } from './graphdb.js';
1616
import { changeGraphQLSchema } from './changes.js';
1717
import { schemaParser, schemaStringify } from './schemaParser.js';
1818
import { validatedSchemaModel} from './schemaModelValidator.js';
19-
import { resolverJS } from './resolverJS.js';
2019
import { getNeptuneSchema, setGetNeptuneSchemaParameters } from './NeptuneSchema.js';
2120
import { createUpdateAWSpipeline, removeAWSpipelineResources } from './pipelineResources.js'
2221
import { createAWSpipelineCDK } from './CDKPipelineApp.js'
@@ -519,11 +518,40 @@ async function main() {
519518
// Validate schema
520519
schemaModel = validatedSchemaModel(schemaModel, quiet);
521520

522-
// Generate AWS Lambda resolver for AppSync and Amazon Neptune
523-
outputLambdaResolver = resolverJS(schemaModel, queryLanguage, queryClient, __dirname);
521+
// Generate schema for resolver
522+
const queryDataModelJSON = JSON.stringify(schemaModel, null, 2);
523+
524+
let resolverSchemaFile;
525+
if (createUpdatePipelineName == '') {
526+
resolverSchemaFile = `${outputFolderPath}/output.resolver.schema.json`
527+
} else {
528+
resolverSchemaFile = `${outputFolderPath}/${createUpdatePipelineName}.resolver.schema.json`
529+
}
530+
531+
try {
532+
writeFileSync(resolverSchemaFile, queryDataModelJSON);
533+
loggerInfo('Wrote schema for resolver to file: ' + yellow(resolverSchemaFile), {toConsole: true});
534+
} catch (err) {
535+
loggerError('Error writing schema for resolver to file: ' + yellow(resolverSchemaFile), err);
536+
}
537+
538+
// Generate AWS Lambda resolver for AppSync and Amazon Neptune
539+
if (queryLanguage == 'opencypher') {
540+
try {
541+
outputLambdaResolver = readFileSync(__dirname + '/../templates/JSResolverOCHTTPS.js');
542+
} catch (err) {
543+
loggerError('No resolver template found.', err);
544+
}
545+
}
524546

525547
// Generate generic Javascript resolver
526-
outputJSResolver = resolverJS(schemaModel, queryLanguage, queryClient, __dirname);
548+
if (queryLanguage == 'opencypher') {
549+
try {
550+
outputJSResolver = readFileSync(__dirname + '/../templates/JSResolverOCHTTPS.js');
551+
} catch (err) {
552+
loggerError('No resolver template found.', err);
553+
}
554+
}
527555
}
528556

529557
// ****************************************************************************
@@ -614,6 +642,12 @@ async function main() {
614642
// output Apollo zip
615643
if (createUpdateApolloServer || createUpdateApolloServerSubgraph) {
616644
const apolloZipPath = path.join(outputFolderPath, `apollo-server-${neptuneInfo.graphName}-${new Date().getTime()}.zip`);
645+
let resolverSchemaFilePath;
646+
if (createUpdatePipelineName == '') {
647+
resolverSchemaFilePath = path.join(outputFolderPath, 'output.resolver.schema.json');
648+
} else {
649+
resolverSchemaFilePath = path.join(outputFolderPath, `${createUpdatePipelineName}.resolver.schema.json`);
650+
}
617651
try {
618652
if (!quiet) {
619653
spinner = ora('Creating Apollo server ZIP file ...').start();
@@ -622,6 +656,7 @@ async function main() {
622656
zipFilePath: apolloZipPath,
623657
resolverFilePath: outputLambdaResolverFile,
624658
schemaFilePath: outputSchemaFile,
659+
resolverSchemaFilePath: resolverSchemaFilePath,
625660
neptuneInfo: neptuneInfo,
626661
isSubgraph: createUpdateApolloServerSubgraph
627662
});

‎src/pipelineResources.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -396,10 +396,12 @@ async function createLambdaRole() {
396396
*/
397397
async function createDeploymentPackage(templateFolderPath, resolverFilePath) {
398398
const zipFilePath = path.join(thisOutputFolderPath, `${NAME}.zip`);
399+
const resolverSchemaFilePath = path.join(thisOutputFolderPath, `${NAME}.resolver.schema.json`)
399400
await createLambdaDeploymentPackage({
400401
outputZipFilePath: zipFilePath,
401402
templateFolderPath: templateFolderPath,
402-
resolverFilePath: resolverFilePath
403+
resolverFilePath: resolverFilePath,
404+
resolverSchemaFilePath: resolverSchemaFilePath
403405
});
404406
await sleep(2000);
405407
const fileContent = await fs.readFileSync(zipFilePath);

‎src/resolverJS.js

-33
This file was deleted.

‎src/zipPackage.js

+12-2
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,22 @@ async function createZip({targetZipFilePath, includePaths = [], includeContent =
4141
* @param outputZipFilePath the path to where the zip should be created
4242
* @param templateFolderPath the path to the template folder that contains contents to add to the zip
4343
* @param resolverFilePath the path to the resolver file that should be added to the zip
44+
* @param resolverSchemaFilePath the path to the resolver schema file that should be added to the zip
4445
* @returns {Promise<Buffer<ArrayBufferLike>>}
4546
*/
46-
export async function createLambdaDeploymentPackage({outputZipFilePath, templateFolderPath, resolverFilePath}) {
47+
export async function createLambdaDeploymentPackage({outputZipFilePath, templateFolderPath, resolverFilePath, resolverSchemaFilePath}) {
4748
const filePaths = [{source: templateFolderPath}, {source: resolverFilePath, target: 'output.resolver.graphql.js'}];
4849
if (templateFolderPath.includes('HTTP')) {
4950
filePaths.push({
5051
source: path.join(getModulePath(), '/../templates/queryHttpNeptune.mjs')
5152
})
5253
}
54+
55+
filePaths.push({
56+
source: resolverSchemaFilePath,
57+
target: 'output.resolver.schema.json'
58+
})
59+
5360
await createZip({
5461
targetZipFilePath: outputZipFilePath,
5562
includePaths: filePaths
@@ -62,11 +69,12 @@ export async function createLambdaDeploymentPackage({outputZipFilePath, template
6269
* @param zipFilePath the file path where the zip should be created
6370
* @param resolverFilePath path to the resolver file to include in the zip
6471
* @param schemaFilePath path to the schema file to include in the zip
72+
* @param resolverSchemaFilePath path to the resolver schema file to include in the zip
6573
* @param neptuneInfo object containing neptune db/graph related information such as URL, region, etc
6674
* @param isSubgraph true if the service should be deployed as a subgraph
6775
* @returns {Promise<void>}
6876
*/
69-
export async function createApolloDeploymentPackage({zipFilePath, resolverFilePath, schemaFilePath, neptuneInfo, isSubgraph = false}) {
77+
export async function createApolloDeploymentPackage({zipFilePath, resolverFilePath, schemaFilePath, resolverSchemaFilePath, neptuneInfo, isSubgraph = false}) {
7078
const envVars = [
7179
`NEPTUNE_TYPE=${neptuneInfo.neptuneType}`,
7280
`NEPTUNE_HOST=${neptuneInfo.host}`,
@@ -82,6 +90,8 @@ export async function createApolloDeploymentPackage({zipFilePath, resolverFilePa
8290
{source: path.join(modulePath, '/../templates/ApolloServer')},
8391
{source: resolverFilePath, target: 'output.resolver.graphql.js'},
8492
{source: schemaFilePath, target: 'output.schema.graphql'},
93+
{source: resolverSchemaFilePath, target: 'output.resolver.schema.json'},
94+
8595
// querying neptune using SDK not yet supported
8696
{source: path.join(modulePath, '/../templates/queryHttpNeptune.mjs')}
8797
],

‎templates/ApolloServer/neptune.mjs

+5-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import {aws4Interceptor} from 'aws4-axios';
44
import {fromNodeProviderChain} from '@aws-sdk/credential-providers';
55
import dotenv from 'dotenv';
66
import {queryNeptune} from './queryHttpNeptune.mjs'
7-
import {resolveGraphDBQueryFromEvent} from "./output.resolver.graphql.js";
7+
import {resolveGraphDBQueryFromEvent, initSchema} from "./output.resolver.graphql.js";
8+
import {readFileSync} from "fs";
89

910

1011
dotenv.config();
@@ -23,6 +24,9 @@ axios.interceptors.request.use(interceptor);
2324
rax.attach();
2425

2526
export async function resolveEvent(event) {
27+
const schemaDataModelJSON = readFileSync('output.resolver.schema.json', 'utf-8');
28+
let schemaModel = JSON.parse(schemaDataModelJSON);
29+
initSchema(schemaModel);
2630
const resolved = resolveGraphDBQueryFromEvent(event);
2731
try {
2832
return queryNeptune(`https://${process.env.NEPTUNE_HOST}:${process.env.NEPTUNE_PORT}`, resolved, {loggingEnabled: loggingEnabled});

‎templates/JSResolverOCHTTPSTemplate.js ‎templates/JSResolverOCHTTPS.js

+11-7
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,18 @@ import { gql } from 'graphql-tag'; // GraphQL library to parse the GraphQL query
1515

1616
const useCallSubquery = false;
1717

18-
// TIMESTAMP HERE
19-
20-
const schemaDataModelJSON = `INSERT SCHEMA DATA MODEL HERE`;
21-
22-
const schemaDataModel = JSON.parse(schemaDataModelJSON);
23-
24-
const schema = buildASTSchema(schemaDataModel, { assumeValidSDL: true });
18+
let schemaDataModel;
19+
let schema;
2520

21+
/**
22+
* Initializes the schema from a given file path
23+
*
24+
* @param {object} schemaModel the path to the JSON schema data mode
25+
*/
26+
export function initSchema(schemaModel) {
27+
schemaDataModel = schemaModel;
28+
schema = buildASTSchema(schemaDataModel, { assumeValidSDL: true });
29+
}
2630

2731
/**
2832
* Resolves a graph db query from a given App Sync graphQL query event.

‎templates/Lambda4AppSyncGraphSDK/index.mjs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {ExecuteQueryCommand, NeptuneGraphClient} from "@aws-sdk/client-neptune-graph";
2-
import {resolveGraphDBQueryFromAppSyncEvent} from './output.resolver.graphql.js';
2+
import {resolveGraphDBQueryFromAppSyncEvent, initSchema} from './output.resolver.graphql.js';
3+
import {readFileSync} from "fs";
34

45
const PROTOCOL = 'https';
56
const QUERY_LANGUAGE = 'OPEN_CYPHER';
@@ -49,6 +50,9 @@ function log(message) {
4950
*/
5051
function resolveGraphQuery(event) {
5152
try {
53+
const schemaDataModelJSON = readFileSync('output.resolver.schema.json', 'utf-8');
54+
let schemaModel = JSON.parse(schemaDataModelJSON);
55+
initSchema(schemaModel);
5256
let resolver = resolveGraphDBQueryFromAppSyncEvent(event);
5357
if (resolver.language !== RESOLVER_LANGUAGE) {
5458
return onError('Unsupported resolver language:' + resolver.language)

‎templates/Lambda4AppSyncHTTP/index.mjs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import axios from "axios";
22
import * as rax from 'retry-axios';
33
import { aws4Interceptor } from "aws4-axios";
4-
import {resolveGraphDBQueryFromAppSyncEvent} from './output.resolver.graphql.js';
4+
import {resolveGraphDBQueryFromAppSyncEvent, initSchema} from './output.resolver.graphql.js';
55
import {queryNeptune} from "./queryHttpNeptune.mjs";
6+
import {readFileSync} from "fs";
67

78
const LOGGING_ENABLED = process.env.LOGGING_ENABLED;
89

@@ -43,6 +44,9 @@ export const handler = async (event) => {
4344
// Create Neptune query from GraphQL query
4445
try {
4546
if (LOGGING_ENABLED) console.log("Event: ", event);
47+
const schemaDataModelJSON = readFileSync('output.resolver.schema.json', 'utf-8');
48+
let schemaModel = JSON.parse(schemaDataModelJSON);
49+
initSchema(schemaModel);
4650
const resolver = resolveGraphDBQueryFromAppSyncEvent(event);
4751
if (LOGGING_ENABLED) console.log("Resolver: ", resolver);
4852
return queryNeptune(`https://${process.env.NEPTUNE_HOST}:${process.env.NEPTUNE_PORT}`, resolver, {loggingEnabled: LOGGING_ENABLED})

‎templates/Lambda4AppSyncSDK/index.mjs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { NeptunedataClient, ExecuteOpenCypherQueryCommand, ExecuteGremlinQueryCommand } from "@aws-sdk/client-neptunedata";
2-
import {resolveGraphDBQueryFromAppSyncEvent, refactorGremlinqueryOutput} from './output.resolver.graphql.js';
2+
import {resolveGraphDBQueryFromAppSyncEvent, refactorGremlinqueryOutput, initSchema} from './output.resolver.graphql.js';
3+
import {readFileSync} from "fs";
34

45
const LOGGING_ENABLED = process.env.LOGGING_ENABLED;
56

@@ -40,6 +41,9 @@ export const handler = async(event) => {
4041
let resolver = { query:'', parameters:{}, language: 'opencypher', fieldsAlias: {} };
4142

4243
try {
44+
const schemaDataModelJSON = readFileSync('output.resolver.schema.json', 'utf-8');
45+
let schemaModel = JSON.parse(schemaDataModelJSON);
46+
initSchema(schemaModel);
4347
resolver = resolveGraphDBQueryFromAppSyncEvent(event);
4448
if (LOGGING_ENABLED) console.log(JSON.stringify(resolver, null, 2));
4549
} catch (error) {

‎test/TestCases/Case01/Case01.03.test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ import { jest } from '@jest/globals';
33
import { testResolverQueries } from '../../testLib';
44

55

6-
await testResolverQueries('./TestCases/Case01/output/output.resolver.graphql.js', './test/TestCases/Case01/queries');
6+
await testResolverQueries('./TestCases/Case01/output/output.resolver.graphql.js', './test/TestCases/Case01/queries', './test/TestCases/Case01/output/output.resolver.schema.json');

‎test/TestCases/Case01/Case01.04.test.js

+1
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ const casetest = readJSONFile('./test/TestCases/Case01/case.json');
66

77
await testResolverQueriesResults( './TestCases/Case01/output/output.resolver.graphql.js',
88
'./test/TestCases/Case01/queries',
9+
'./test/TestCases/Case01/output/output.resolver.schema.json',
910
casetest.host,
1011
casetest.port);

‎test/TestCases/Case01/Case01.05.test.js

+4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11

22
import { jest } from '@jest/globals';
33
import { loadResolver } from '../../testLib';
4+
import {readFileSync} from "fs";
45

56
describe('AppSync resolver', () => {
67
let resolverModule;
78

89
beforeAll(async () => {
910
resolverModule = await loadResolver('./TestCases/Case01/output/output.resolver.graphql.js');
11+
const schemaDataModelJSON = readFileSync('./test/TestCases/Case01/output/output.resolver.schema.json', 'utf-8');
12+
let schemaModel = JSON.parse(schemaDataModelJSON);
13+
resolverModule.initSchema(schemaModel);
1014
});
1115

1216
test('should resolve queries with a filter', () => {

0 commit comments

Comments
 (0)
Please sign in to comment.