Skip to content

Commit 5a6b63e

Browse files
committed
Added Auth Lambda
1 parent a9f3ee2 commit 5a6b63e

16 files changed

+1270
-704
lines changed

bin/chat_api_app_sync.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
11
#!/usr/bin/env node
2-
import 'source-map-support/register';
3-
import * as cdk from '@aws-cdk/core';
4-
import { ChatApiAppSyncStack } from '../lib/chat_api_app_sync-stack';
2+
import "source-map-support/register";
3+
import * as cdk from "@aws-cdk/core";
4+
import { ChatApiAppSyncStack } from "../lib/chat_api_app_sync-stack";
55

66
const app = new cdk.App();
7-
new ChatApiAppSyncStack(app, 'ChatApiAppSyncStack', {
7+
new ChatApiAppSyncStack(app, "ChatApiAppSyncStack", {
88
/* If you don't specify 'env', this stack will be environment-agnostic.
99
* Account/Region-dependent features and context lookups will not work,
1010
* but a single synthesized template can be deployed anywhere. */
11-
1211
/* Uncomment the next line to specialize this stack for the AWS Account
1312
* and Region that are implied by the current CLI configuration. */
1413
// env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
15-
1614
/* Uncomment the next line if you know exactly what Account and Region you
1715
* want to deploy the stack to. */
1816
// env: { account: '123456789012', region: 'us-east-1' },
19-
2017
/* For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html */
18+
env: { region: "ap-south-1" },
2119
});

lib/auth-lambda.construct.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import * as cdk from "@aws-cdk/core";
2+
import * as iam from "@aws-cdk/aws-iam";
3+
import * as nodeLambda from "@aws-cdk/aws-lambda-nodejs";
4+
5+
export class AuthLambdaConstruct extends cdk.Stack {
6+
readonly lambda: nodeLambda.NodejsFunction;
7+
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
8+
super(scope, id, props);
9+
10+
this.lambda = new nodeLambda.NodejsFunction(this, "AppSyncAuthHandler", {
11+
functionName: `custom-authoriser`,
12+
description: `This Lambda is excuted fauthenticate the user.`,
13+
retryAttempts: 0,
14+
entry: "src/lambdas/auth.ts",
15+
handler: "handler",
16+
});
17+
18+
this.lambda.grantInvoke(new iam.ServicePrincipal("appsync.amazonaws.com"));
19+
}
20+
}

lib/chat_api_app_sync-stack.ts

Lines changed: 41 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,115 +1,65 @@
11
import * as cdk from "@aws-cdk/core";
2-
import * as cdkCore from "@aws-cdk/core";
3-
import * as appsync from "@aws-cdk/aws-appsync";
4-
import * as dynamoDb from "@aws-cdk/aws-dynamoDb";
5-
import * as lambda from "@aws-cdk/aws-lambda";
6-
// import { Code, Function, Runtime } from '@aws-cdk/aws-lambda';
7-
// import * as sqs from '@aws-cdk/aws-sqs';
2+
import { GraphQlAPIConstruct } from "./graph-api.construct";
3+
import { LambdaConstruct } from "./lambda.contruct";
4+
import { DynamoDBConstruct } from "./dynamo-db.construct";
85

96
export class ChatApiAppSyncStack extends cdk.Stack {
107
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
118
super(scope, id, props);
129

13-
const MessagesTable = new dynamoDb.Table(this, "MessagesTable", {
14-
billingMode: dynamoDb.BillingMode.PAY_PER_REQUEST,
15-
partitionKey: { name: "id", type: dynamoDb.AttributeType.STRING },
16-
sortKey: { name: "conversationId", type: dynamoDb.AttributeType.STRING },
17-
removalPolicy: cdkCore.RemovalPolicy.DESTROY,
18-
tableName: "messages-table",
19-
});
10+
const dynamoDBConstruct = new DynamoDBConstruct(
11+
this,
12+
`${id}-dynamo-db`,
13+
props
14+
);
2015

21-
const ConversationsTable = new dynamoDb.Table(this, "ConversationsTable", {
22-
billingMode: dynamoDb.BillingMode.PAY_PER_REQUEST,
23-
partitionKey: { name: "id", type: dynamoDb.AttributeType.STRING },
24-
removalPolicy: cdkCore.RemovalPolicy.DESTROY,
25-
tableName: "conversations-table",
26-
});
16+
const lambdaConstruct = new LambdaConstruct(this, `${id}-lambda`, props);
2717

28-
const UsersTable = new dynamoDb.Table(this, "UsersTable", {
29-
billingMode: dynamoDb.BillingMode.PAY_PER_REQUEST,
30-
partitionKey: { name: "id", type: dynamoDb.AttributeType.STRING },
31-
removalPolicy: cdkCore.RemovalPolicy.DESTROY,
32-
tableName: "users-table",
33-
});
18+
const graphAPIContruct = new GraphQlAPIConstruct(
19+
this,
20+
`${id}-graph-api`,
21+
props
22+
);
3423

35-
const api = new appsync.GraphqlApi(this, "ChatsApi", {
36-
name: "chat-api",
37-
logConfig: {
38-
fieldLogLevel: appsync.FieldLogLevel.ERROR,
39-
},
40-
schema: appsync.Schema.fromAsset("src/graphql/schema.graphql"),
41-
authorizationConfig: {
42-
defaultAuthorization: {
43-
authorizationType: appsync.AuthorizationType.API_KEY,
44-
apiKeyConfig: {
45-
expires: cdk.Expiration.after(cdk.Duration.days(365)),
46-
},
47-
},
48-
},
49-
// xrayEnabled: true,
50-
});
24+
// enable the Lambda function to access the DynamoDB table (using IAM)
25+
dynamoDBConstruct.messagesTable.grantFullAccess(lambdaConstruct.lambda);
26+
dynamoDBConstruct.notificationTable.grantFullAccess(lambdaConstruct.lambda);
27+
dynamoDBConstruct.conversationsTable.grantFullAccess(
28+
lambdaConstruct.lambda
29+
);
30+
dynamoDBConstruct.usersTable.grantFullAccess(lambdaConstruct.lambda);
31+
32+
// Create an environment variable that we will use in the function code
33+
lambdaConstruct.lambda.addEnvironment(
34+
"MESSAGES_TABLE",
35+
dynamoDBConstruct.messagesTable.tableName
36+
);
37+
lambdaConstruct.lambda.addEnvironment(
38+
"CONVERSATIONS_TABLE",
39+
dynamoDBConstruct.conversationsTable.tableName
40+
);
41+
lambdaConstruct.lambda.addEnvironment(
42+
"USERS_TABLE",
43+
dynamoDBConstruct.usersTable.tableName
44+
);
45+
lambdaConstruct.lambda.addEnvironment(
46+
"NOTIFICATIONS_TABLE",
47+
dynamoDBConstruct.notificationTable.tableName
48+
);
5149

5250
// Prints out the AppSync GraphQL endpoint to the terminal
5351
new cdk.CfnOutput(this, "GraphQLAPIURL", {
54-
value: api.graphqlUrl,
52+
value: graphAPIContruct.api.graphqlUrl,
5553
});
5654

5755
// Prints out the AppSync GraphQL API key to the terminal
5856
new cdk.CfnOutput(this, "GraphQLAPIKey", {
59-
value: api.apiKey || "",
57+
value: graphAPIContruct.api.apiKey || "",
6058
});
6159

6260
// Prints out the stack region to the terminal
6361
new cdk.CfnOutput(this, "Stack Region", {
6462
value: this.region,
6563
});
66-
67-
// const chatsLambda = new lambda.Function(this, "AppSyncChatRouteHandler", {
68-
// runtime: lambda.Runtime.NODEJS_12_X,
69-
// handler: "routes.handler",
70-
// code: lambda.Code.fromAsset("src"),
71-
// memorySize: 1024,
72-
// });
73-
74-
// // Set the new Lambda function as a data source for the AppSync API
75-
// const lambdaDs = api.addLambdaDataSource("lambdaDatasource", chatsLambda);
76-
77-
// lambdaDs.createResolver({
78-
// typeName: "Query",
79-
// fieldName: "getConversations",
80-
// });
81-
82-
// lambdaDs.createResolver({
83-
// typeName: "Query",
84-
// fieldName: "getConversation",
85-
// });
86-
87-
// lambdaDs.createResolver({
88-
// typeName: "Mutation",
89-
// fieldName: "addConversation",
90-
// });
91-
92-
// lambdaDs.createResolver({
93-
// typeName: "Mutation",
94-
// fieldName: "addMessage",
95-
// });
96-
97-
// lambdaDs.createResolver({
98-
// typeName: "Mutation",
99-
// fieldName: "addUser",
100-
// });
101-
102-
// enable the Lambda function to access the DynamoDB table (using IAM)
103-
// MessagesTable.grantFullAccess(chatsLambda);
104-
// ConversationsTable.grantFullAccess(chatsLambda);
105-
// UsersTable.grantFullAccess(chatsLambda);
106-
107-
// // Create an environment variable that we will use in the function code
108-
// chatsLambda.addEnvironment("MESSAGES_TABLE", MessagesTable.tableName);
109-
// chatsLambda.addEnvironment(
110-
// "CONVERSATIONS_TABLE",
111-
// ConversationsTable.tableName
112-
// );
113-
// chatsLambda.addEnvironment("USERS_TABLE", UsersTable.tableName);
11464
}
11565
}

lib/dynamo-db.construct.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import * as cdk from "@aws-cdk/core";
2+
import * as dynamoDb from "@aws-cdk/aws-dynamoDb";
3+
4+
export class DynamoDBConstruct extends cdk.Stack {
5+
readonly messagesTable: dynamoDb.Table;
6+
readonly conversationsTable: dynamoDb.Table;
7+
readonly usersTable: dynamoDb.Table;
8+
readonly notificationTable: dynamoDb.Table;
9+
10+
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
11+
super(scope, id, props);
12+
13+
this.messagesTable = new dynamoDb.Table(this, "MessagesTable", {
14+
billingMode: dynamoDb.BillingMode.PAY_PER_REQUEST,
15+
partitionKey: { name: "conversationId", type: dynamoDb.AttributeType.STRING },
16+
sortKey: { name: "createdAt", type: dynamoDb.AttributeType.STRING },
17+
removalPolicy: cdk.RemovalPolicy.DESTROY,
18+
tableName: "messages-table",
19+
});
20+
21+
this.conversationsTable = new dynamoDb.Table(this, "ConversationsTable", {
22+
billingMode: dynamoDb.BillingMode.PAY_PER_REQUEST,
23+
partitionKey: { name: "id", type: dynamoDb.AttributeType.STRING },
24+
removalPolicy: cdk.RemovalPolicy.DESTROY,
25+
tableName: "conversations-table",
26+
});
27+
28+
this.usersTable = new dynamoDb.Table(this, "UsersTable", {
29+
billingMode: dynamoDb.BillingMode.PAY_PER_REQUEST,
30+
partitionKey: { name: "id", type: dynamoDb.AttributeType.STRING },
31+
removalPolicy: cdk.RemovalPolicy.DESTROY,
32+
tableName: "users-table",
33+
});
34+
35+
this.notificationTable = new dynamoDb.Table(this, "NotificationsTable", {
36+
billingMode: dynamoDb.BillingMode.PAY_PER_REQUEST,
37+
partitionKey: { name: "id", type: dynamoDb.AttributeType.STRING },
38+
sortKey: { name: "createdAt", type: dynamoDb.AttributeType.STRING },
39+
removalPolicy: cdk.RemovalPolicy.DESTROY,
40+
tableName: "notifications-table",
41+
});
42+
}
43+
}

lib/graph-api.construct.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import * as cdk from "@aws-cdk/core";
2+
import * as appsync from "@aws-cdk/aws-appsync";
3+
import * as nodeLambda from "@aws-cdk/aws-lambda-nodejs";
4+
import * as iam from "@aws-cdk/aws-iam";
5+
import { AuthLambdaConstruct } from "./auth-lambda.construct";
6+
7+
export class GraphQlAPIConstruct extends cdk.Stack {
8+
readonly api: appsync.GraphqlApi;
9+
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
10+
super(scope, id, props);
11+
12+
const athLambdaConstruct = new AuthLambdaConstruct(
13+
this,
14+
`${id}-auth-lambda`,
15+
props
16+
);
17+
18+
this.api = new appsync.GraphqlApi(this, "ChatsApi", {
19+
name: "chat-api",
20+
schema: appsync.Schema.fromAsset("src/graphql/schema.graphql"),
21+
authorizationConfig: {
22+
defaultAuthorization: {
23+
authorizationType: appsync.AuthorizationType.LAMBDA,
24+
lambdaAuthorizerConfig: {
25+
handler: athLambdaConstruct.lambda,
26+
},
27+
// // API Key Authentication
28+
// authorizationType: appsync.AuthorizationType.API_KEY,
29+
// apiKeyConfig: {
30+
// expires: cdk.Expiration.after(cdk.Duration.days(365)),
31+
// },
32+
},
33+
},
34+
});
35+
}
36+
}

lib/graphql/graphql-resolvers.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import * as appsync from "@aws-cdk/aws-appsync";
2+
import * as nodeLambda from "@aws-cdk/aws-lambda-nodejs";
3+
4+
export const bindResolvers = (
5+
api: appsync.GraphqlApi,
6+
lambda: nodeLambda.NodejsFunction
7+
) => {
8+
// Set the new Lambda function as a data source for the AppSync API
9+
const lambdaDs = api.addLambdaDataSource("lambdaDatasource", lambda);
10+
11+
lambdaDs.createResolver({
12+
typeName: "Query",
13+
fieldName: "conversations",
14+
});
15+
16+
lambdaDs.createResolver({
17+
typeName: "Query",
18+
fieldName: "users",
19+
});
20+
21+
lambdaDs.createResolver({
22+
typeName: "Query",
23+
fieldName: "conversation",
24+
});
25+
26+
lambdaDs.createResolver({
27+
typeName: "Query",
28+
fieldName: "notifications",
29+
});
30+
31+
lambdaDs.createResolver({
32+
typeName: "Mutation",
33+
fieldName: "createConversation",
34+
});
35+
36+
lambdaDs.createResolver({
37+
typeName: "Mutation",
38+
fieldName: "addMessage",
39+
});
40+
41+
lambdaDs.createResolver({
42+
typeName: "Mutation",
43+
fieldName: "createUser",
44+
});
45+
46+
lambdaDs.createResolver({
47+
typeName: "Mutation",
48+
fieldName: "addNotification",
49+
});
50+
51+
lambdaDs.createResolver({
52+
typeName: "Subscription",
53+
fieldName: "onCreateUser",
54+
});
55+
56+
lambdaDs.createResolver({
57+
typeName: "Subscription",
58+
fieldName: "onCreateNotification",
59+
});
60+
};

lib/lambda.contruct.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import * as cdk from "@aws-cdk/core";
2+
import * as nodeLambda from "@aws-cdk/aws-lambda-nodejs";
3+
4+
export class LambdaConstruct extends cdk.Stack {
5+
readonly lambda: nodeLambda.NodejsFunction;
6+
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
7+
super(scope, id, props);
8+
9+
this.lambda = new nodeLambda.NodejsFunction(
10+
this,
11+
"AppSyncChatRouteHandler",
12+
{
13+
functionName: `chat-routing`,
14+
description: `This Lambda is excuted from graphql to trigger lambda.`,
15+
retryAttempts: 0,
16+
entry: "src/routes.ts",
17+
handler: "handler",
18+
}
19+
);
20+
}
21+
}

0 commit comments

Comments
 (0)