in source/cdk-infrastructure/lib/back-end/appsync-api/appsync-api-construct.ts [30:324]
constructor(scope: Construct, id: string, props: AppSyncApiProps) {
super(scope, id);
const sourceCodeBucket = Bucket.fromBucketName(this, 'sourceCodeBucket', props.sourceCodeBucketName);
this.issuesTable = this.createTable(AVATableLogicalIds.ISSUES_TABLE);
this.dataHierarchyTable = this.createTable(AVATableLogicalIds.DATA_HIERARCHY_TABLE);
const logRole = new Role(this, 'LogRole', {
assumedBy: new ServicePrincipal('appsync.amazonaws.com'),
path: '/'
});
logRole.addToPrincipalPolicy(new PolicyStatement({
effect: Effect.ALLOW,
actions: ['logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents'],
resources: [Stack.of(this).formatArn({ service: 'logs', resource: 'log-group', resourceName: '*', arnFormat: ArnFormat.COLON_RESOURCE_NAME })]
}));
this.graphqlApi = new GraphqlApi(this, 'GraphqlApi', {
name: 'ava-api',
schema: Schema.fromAsset(`${__dirname}/schema.graphql`),
authorizationConfig: {
defaultAuthorization: {
authorizationType: AuthorizationType.USER_POOL,
userPoolConfig: {
userPool: props.userPool,
defaultAction: UserPoolDefaultAction.ALLOW
}
},
additionalAuthorizationModes: [{
authorizationType: AuthorizationType.IAM
}]
},
logConfig: { fieldLogLevel: FieldLogLevel.NONE, excludeVerboseContent: false, role: logRole }
});
const issuesDataSource = this.graphqlApi.addDynamoDbDataSource('IssueDataSource', this.issuesTable);
const dataHierarchyDataSource = this.graphqlApi.addDynamoDbDataSource('AVADataSource', this.dataHierarchyTable);
const noneDataSource = this.graphqlApi.addNoneDataSource('NoneDataSource');
const avaResolverLambdaFnRole = new Role(this, 'AppSyncResolverLambdaFunctionRole', {
assumedBy: new ServicePrincipal('lambda.amazonaws.com'),
path: '/',
inlinePolicies: {
'SnsPolicy': new PolicyDocument({
statements: [new PolicyStatement({
effect: Effect.ALLOW,
actions: ['sns:Subscribe', 'sns:Unsubscribe', 'sns:SetSubscriptionAttributes'],
resources: [props.issueNotificationTopicArn]
})]
}),
'DynamoDbPolicy': new PolicyDocument({
statements: [
new PolicyStatement({
effect: Effect.ALLOW,
actions: ['dynamodb:GetItem', 'dynamodb:PutItem'],
resources: [this.dataHierarchyTable.tableArn]
}),
new PolicyStatement({
effect: Effect.ALLOW,
actions: ['dynamodb:Query'],
resources: [`${this.issuesTable.tableArn}/index/ByCreatedDate-index`]
})
]
}),
'CloudWatchLogsPolicy': new PolicyDocument({
statements: [new PolicyStatement({
effect: Effect.ALLOW,
actions: ['logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents'],
resources: [Stack.of(this).formatArn({ service: 'logs', resource: 'log-group', resourceName: '/aws/lambda/*', arnFormat: ArnFormat.COLON_RESOURCE_NAME })]
})]
})
}
});
const avaResolverLambdaFn = new LambdaFunction(this, 'AppSyncResolverLambdaFunction', {
runtime: Runtime.NODEJS_14_X,
handler: 'appsync-lambda-resolver/index.handler',
timeout: Duration.seconds(60),
description: `${props.solutionDisplayName} (${props.solutionVersion}): Resolver for various AppSync functions`,
code: Code.fromBucket(sourceCodeBucket, [props.sourceCodeKeyPrefix, 'appsync-lambda-resolver.zip'].join('/')),
role: avaResolverLambdaFnRole,
environment: {
LOGGING_LEVEL: props.loggingLevel,
ISSUE_NOTIFICATION_TOPIC_ARN: props.issueNotificationTopicArn,
DATA_HIERARCHY_TABLE_NAME: this.dataHierarchyTable.tableName,
ISSUES_TABLE_NAME: this.issuesTable.tableName
}
});
const avaLambdaDataSource = this.graphqlApi.addLambdaDataSource('AVALambdaDataSource', avaResolverLambdaFn);
const appsyncFunctions = {
getPermissionsForAssociateGroupUserFunction: this.getFunction({ dataSource: dataHierarchyDataSource, name: 'GetPermissionsForAssociateGroupUserFunction', description: 'Get permissions for an associate group user', reqTemplateStr: 'Query.get.req.vtl' }),
listSitesFunction: this.getFunction({ dataSource: dataHierarchyDataSource, name: 'ListSitesFunction', description: 'Get sites', reqTemplateStr: 'Query.listSites.req.vtl' }),
createRootCauseFunction: this.getFunction({ dataSource: dataHierarchyDataSource, name: 'CreateRootCauseFunction', description: 'Create a root cause', reqTemplateStr: 'Mutation.create.req.vtl' }),
listRootCausesByNameFunction: this.getFunction({ dataSource: dataHierarchyDataSource, name: 'ListRootCausesByNameFunction', description: 'Get root causes', reqTemplateStr: 'Query.listRootCausesByName.req.vtl' }),
listSitesByNameFunction: this.getFunction({ dataSource: dataHierarchyDataSource, name: 'ListSitesByNameFunction', description: 'Get sites by name', reqTemplateStr: 'Query.listSitesByName.req.vtl' }),
createSiteFunction: this.getFunction({ dataSource: dataHierarchyDataSource, name: 'CreateSiteFunction', description: 'Create a site', reqTemplateStr: 'Mutation.create.req.vtl' }),
listAreasFunction: this.getFunction({ dataSource: dataHierarchyDataSource, name: 'ListAreasFunction', description: 'Get areas', reqTemplateStr: 'Query.listAreas.req.vtl' }),
createAreaFunction: this.getFunction({ dataSource: dataHierarchyDataSource, name: 'CreateAreaFunction', description: 'Create an area', reqTemplateStr: 'Mutation.create.req.vtl' }),
listStationsFunction: this.getFunction({ dataSource: dataHierarchyDataSource, name: 'ListStationsFunction', description: 'Get stations', reqTemplateStr: 'Query.listStations.req.vtl' }),
createStationFunction: this.getFunction({ dataSource: dataHierarchyDataSource, name: 'CreateStationFunction', description: 'Create a station', reqTemplateStr: 'Mutation.create.req.vtl' }),
listProcessesFunction: this.getFunction({ dataSource: dataHierarchyDataSource, name: 'ListProcessesFunction', description: 'Get processes', reqTemplateStr: 'Query.listProcesses.req.vtl' }),
createProcessFunction: this.getFunction({ dataSource: dataHierarchyDataSource, name: 'CreateProcessFunction', description: 'Create a process', reqTemplateStr: 'Mutation.create.req.vtl' }),
listDevicesFunction: this.getFunction({ dataSource: dataHierarchyDataSource, name: 'ListDevicesFunction', description: 'Get devices', reqTemplateStr: 'Query.listDevices.req.vtl' }),
createDeviceFunction: this.getFunction({ dataSource: dataHierarchyDataSource, name: 'CreateDeviceFunction', description: 'Create a device', reqTemplateStr: 'Mutation.create.req.vtl' }),
listEventsFunction: this.getFunction({ dataSource: dataHierarchyDataSource, name: 'ListEventsFunction', description: 'Get events', reqTemplateStr: 'Query.listEvents.req.vtl' }),
createEventFunction: this.getFunction({ dataSource: dataHierarchyDataSource, name: 'CreateEventFunction', description: 'Create an event', reqTemplateStr: 'Mutation.create.req.vtl' }),
updateEventFunction: this.getFunction({ dataSource: dataHierarchyDataSource, name: 'UpdateEventFunction', description: 'Update an event', reqTemplateStr: 'Mutation.updateEvent.req.vtl' }),
deleteEventFunction: this.getFunction({ dataSource: dataHierarchyDataSource, name: 'DeleteEventFunction', description: 'Delete an event', reqTemplateStr: 'Mutation.delete.req.vtl' }),
handleEventSnsFunction: avaLambdaDataSource.createFunction({ name: 'HandleEventSnsFunction', description: 'Manages SNS Subscriptions to the main AVA Topic' }),
listIssuesByDeviceFunction: this.getFunction({ dataSource: issuesDataSource, name: 'ListIssuesByDeviceFunction', description: 'Get issues by device', reqTemplateStr: 'Query.issuesByDevice.req.vtl' })
};
this.getResolver({ typeName: 'Site', fieldName: 'area', dataSource: dataHierarchyDataSource, reqTemplateStr: 'Site.area.req.vtl' });
this.getResolver({ typeName: 'Area', fieldName: 'site', dataSource: dataHierarchyDataSource, reqTemplateStr: 'Area.site.req.vtl' });
this.getResolver({ typeName: 'Area', fieldName: 'process', dataSource: dataHierarchyDataSource, reqTemplateStr: 'Area.process.req.vtl' });
this.getResolver({ typeName: 'Area', fieldName: 'station', dataSource: dataHierarchyDataSource, reqTemplateStr: 'Area.station.req.vtl' });
this.getResolver({ typeName: 'Process', fieldName: 'area', dataSource: dataHierarchyDataSource, reqTemplateStr: 'Process.area.req.vtl' });
this.getResolver({ typeName: 'Process', fieldName: 'event', dataSource: dataHierarchyDataSource, reqTemplateStr: 'Process.event.req.vtl' });
this.getResolver({ typeName: 'Event', fieldName: 'process', dataSource: dataHierarchyDataSource, reqTemplateStr: 'Event.process.req.vtl' });
this.getResolver({ typeName: 'Station', fieldName: 'area', dataSource: dataHierarchyDataSource, reqTemplateStr: 'Station.area.req.vtl' });
this.getResolver({ typeName: 'Station', fieldName: 'device', dataSource: dataHierarchyDataSource, reqTemplateStr: 'Station.device.req.vtl' });
this.getResolver({ typeName: 'Device', fieldName: 'station', dataSource: dataHierarchyDataSource, reqTemplateStr: 'Device.station.req.vtl' });
this.getResolver({ typeName: 'Query', fieldName: 'getSite', dataSource: dataHierarchyDataSource, reqTemplateStr: 'Query.get.req.vtl' });
this.getResolver({
typeName: 'Query',
fieldName: 'listSites',
pipelineFunctions: [appsyncFunctions.getPermissionsForAssociateGroupUserFunction, appsyncFunctions.listSitesFunction],
reqTemplateStr: `
$util.qr($ctx.stash.put("permissionCheck", true))
$util.qr($ctx.stash.put("type", "site"))
{}`.trim(),
resTemplateStr: 'Response.prev.vtl'
});
this.getResolver({
typeName: 'Mutation',
fieldName: 'createSite',
pipelineFunctions: [appsyncFunctions.listSitesByNameFunction, appsyncFunctions.createSiteFunction],
reqTemplateStr: '{}',
resTemplateStr: 'Response.prev.vtl'
});
this.getResolver({ typeName: 'Mutation', fieldName: 'deleteSite', dataSource: dataHierarchyDataSource, reqTemplateStr: 'Mutation.delete.req.vtl' });
this.getResolver({ typeName: 'Query', fieldName: 'getArea', dataSource: dataHierarchyDataSource, reqTemplateStr: 'Query.get.req.vtl' });
this.getResolver({
typeName: 'Query',
fieldName: 'listAreas',
pipelineFunctions: [appsyncFunctions.getPermissionsForAssociateGroupUserFunction, appsyncFunctions.listAreasFunction],
reqTemplateStr: `
$util.qr($ctx.stash.put("permissionCheck", true))
$util.qr($ctx.stash.put("type", "area"))
{}`.trim(),
resTemplateStr: 'Response.prev.vtl'
});
this.getResolver({
typeName: 'Mutation',
fieldName: 'createArea',
pipelineFunctions: [appsyncFunctions.listAreasFunction, appsyncFunctions.createAreaFunction],
reqTemplateStr: '{}',
resTemplateStr: 'Response.prev.vtl'
});
this.getResolver({ typeName: 'Mutation', fieldName: 'deleteArea', dataSource: dataHierarchyDataSource, reqTemplateStr: 'Mutation.delete.req.vtl' });
this.getResolver({ typeName: 'Query', fieldName: 'getStation', dataSource: dataHierarchyDataSource, reqTemplateStr: 'Query.get.req.vtl' });
this.getResolver({
typeName: 'Query',
fieldName: 'listStations',
pipelineFunctions: [appsyncFunctions.getPermissionsForAssociateGroupUserFunction, appsyncFunctions.listStationsFunction],
reqTemplateStr: `
$util.qr($ctx.stash.put("permissionCheck", true))
$util.qr($ctx.stash.put("type", "station"))
{}`.trim(),
resTemplateStr: 'Response.prev.vtl'
});
this.getResolver({
typeName: 'Mutation',
fieldName: 'createStation',
pipelineFunctions: [appsyncFunctions.listStationsFunction, appsyncFunctions.createStationFunction],
reqTemplateStr: '{}',
resTemplateStr: 'Response.prev.vtl'
});
this.getResolver({ typeName: 'Mutation', fieldName: 'deleteStation', dataSource: dataHierarchyDataSource, reqTemplateStr: 'Mutation.delete.req.vtl' });
this.getResolver({ typeName: 'Query', fieldName: 'getProcess', dataSource: dataHierarchyDataSource, reqTemplateStr: 'Query.get.req.vtl' });
this.getResolver({
typeName: 'Query',
fieldName: 'listProcesses',
pipelineFunctions: [appsyncFunctions.getPermissionsForAssociateGroupUserFunction, appsyncFunctions.listProcessesFunction],
reqTemplateStr: `
$util.qr($ctx.stash.put("permissionCheck", true))
$util.qr($ctx.stash.put("type", "process"))
{}`.trim(),
resTemplateStr: 'Response.prev.vtl'
});
this.getResolver({
typeName: 'Mutation',
fieldName: 'createProcess',
pipelineFunctions: [appsyncFunctions.listProcessesFunction, appsyncFunctions.createProcessFunction],
reqTemplateStr: '{}',
resTemplateStr: 'Response.prev.vtl'
});
this.getResolver({ typeName: 'Mutation', fieldName: 'deleteProcess', dataSource: dataHierarchyDataSource, reqTemplateStr: 'Mutation.delete.req.vtl' });
this.getResolver({
typeName: 'Query',
fieldName: 'listDevices',
pipelineFunctions: [appsyncFunctions.getPermissionsForAssociateGroupUserFunction, appsyncFunctions.listDevicesFunction],
reqTemplateStr: `
$util.qr($ctx.stash.put("permissionCheck", true))
$util.qr($ctx.stash.put("type", "device"))
{}`.trim(),
resTemplateStr: 'Response.prev.vtl'
});
this.getResolver({
typeName: 'Mutation',
fieldName: 'createDevice',
pipelineFunctions: [appsyncFunctions.listDevicesFunction, appsyncFunctions.createDeviceFunction],
reqTemplateStr: '{}',
resTemplateStr: 'Response.prev.vtl'
});
this.getResolver({ typeName: 'Mutation', fieldName: 'deleteDevice', dataSource: dataHierarchyDataSource, reqTemplateStr: 'Mutation.delete.req.vtl' });
this.getResolver({ typeName: 'Query', fieldName: 'getEvent', dataSource: dataHierarchyDataSource, reqTemplateStr: 'Query.get.req.vtl' });
this.getResolver({
typeName: 'Query',
fieldName: 'listEvents',
pipelineFunctions: [appsyncFunctions.getPermissionsForAssociateGroupUserFunction, appsyncFunctions.listEventsFunction],
reqTemplateStr: `
$util.qr($ctx.stash.put("permissionCheck", true))
$util.qr($ctx.stash.put("type", "event"))
{}`.trim(),
resTemplateStr: 'Response.prev.vtl'
});
this.getResolver({
typeName: 'Mutation',
fieldName: 'createEvent',
pipelineFunctions: [appsyncFunctions.listEventsFunction, appsyncFunctions.createEventFunction, appsyncFunctions.handleEventSnsFunction],
reqTemplateStr: '{}',
resTemplateStr: 'Response.prev.vtl'
});
this.getResolver({
typeName: 'Mutation',
fieldName: 'updateEvent',
pipelineFunctions: [appsyncFunctions.updateEventFunction, appsyncFunctions.handleEventSnsFunction],
reqTemplateStr: '{}',
resTemplateStr: 'Response.prev.vtl'
});
this.getResolver({
typeName: 'Mutation',
fieldName: 'deleteEvent',
pipelineFunctions: [appsyncFunctions.deleteEventFunction, appsyncFunctions.handleEventSnsFunction],
reqTemplateStr: '{}',
resTemplateStr: 'Response.prev.vtl'
});
this.getResolver({ typeName: 'Mutation', fieldName: 'createIssue', dataSource: issuesDataSource, reqTemplateStr: 'Mutation.createIssue.req.vtl' });
this.getResolver({ typeName: 'Mutation', fieldName: 'updateIssue', dataSource: issuesDataSource, reqTemplateStr: 'Mutation.updateIssue.req.vtl' });
this.getResolver({ typeName: 'Query', fieldName: 'issuesBySiteAreaStatus', dataSource: issuesDataSource, reqTemplateStr: 'Query.issuesBySiteAreaStatus.req.vtl' });
this.getResolver({
typeName: 'Query',
fieldName: 'issuesByDevice',
pipelineFunctions: [appsyncFunctions.getPermissionsForAssociateGroupUserFunction, appsyncFunctions.listIssuesByDeviceFunction],
reqTemplateStr: `
$util.qr($ctx.stash.put("permissionCheck", true))
$util.qr($ctx.stash.put("type", "issue"))
{}`.trim(),
resTemplateStr: 'Response.prev.vtl'
});
this.getResolver({ typeName: 'Mutation', fieldName: 'putPermission', dataSource: dataHierarchyDataSource, reqTemplateStr: 'Mutation.putPermission.req.vtl' });
this.getResolver({ typeName: 'Mutation', fieldName: 'deletePermission', dataSource: dataHierarchyDataSource, reqTemplateStr: 'Mutation.delete.req.vtl' });
this.getResolver({ typeName: 'Query', fieldName: 'getPermission', dataSource: dataHierarchyDataSource, reqTemplateStr: 'Query.get.req.vtl' });
this.getResolver({ typeName: 'Query', fieldName: 'listPermissions', dataSource: dataHierarchyDataSource, reqTemplateStr: 'Query.listPermissions.req.vtl' });
this.getResolver({ typeName: 'Query', fieldName: 'listRootCauses', dataSource: dataHierarchyDataSource, reqTemplateStr: 'Query.listRootCauses.req.vtl' });
this.getResolver({
typeName: 'Mutation',
fieldName: 'createRootCause',
pipelineFunctions: [appsyncFunctions.listRootCausesByNameFunction, appsyncFunctions.createRootCauseFunction],
reqTemplateStr: '{}',
resTemplateStr: 'Response.prev.vtl'
});
this.getResolver({ typeName: 'Mutation', fieldName: 'deleteRootCause', dataSource: dataHierarchyDataSource, reqTemplateStr: 'Mutation.delete.req.vtl' });
avaLambdaDataSource.createResolver({ typeName: 'Query', fieldName: 'getPrevDayIssuesStats' });
// Create subscriptions
['onCreateIssue', 'onUpdateIssue', 'onPutPermission', 'onDeletePermission', 'onCreateRootCause', 'onDeleteRootCause'].forEach(fieldName => {
this.graphqlApi.createResolver({
typeName: 'Subscription',
dataSource: noneDataSource,
fieldName,
requestMappingTemplate: MappingTemplate.fromString(`
{
"version": "2018-05-29",
"payload": {}
}`),
responseMappingTemplate: MappingTemplate.fromFile(`${__dirname}/resolver/Subscription.res.vtl`)
});
});
}