Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions typescript/s3-sns-filter-lambda/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
{
"extends": [
"eslint:recommended",
"eslint-config-airbnb-base",
"airbnb-typescript",
"plugin:@typescript-eslint/recommended",
"prettier"
],
"env": {
"es2021": true,
"node": true
},
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint", "prettier"],
"rules": {
"@typescript-eslint/no-unused-vars": "error",
"import/prefer-default-export": "off",
"no-tabs": ["off"],
"max-len": ["off"],
"no-await-in-loop": "off",
"react/jsx-filename-extension": "off",
"class-methods-use-this": "off",
"no-new": "off",
"no-param-reassign": "off",
"@typescript-eslint/quotes": [
"error",
"single",
{
"avoidEscape": true
}
],
"@typescript-eslint/comma-dangle": ["error", "never"],
"@typescript-eslint/no-namespace": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/lines-between-class-members": [
"error",
"always",
{
"exceptAfterSingleLine": true
}
],
"prettier/prettier": [
"error",
{
"tabWidth": 2
}
]
},
"overrides": [
{
"files": ["*.spec.{js,ts}"],
"env": {
"mocha": true,
"node": true
},
"rules": {
"no-unused-expressions": "off",
"@typescript-eslint/no-unused-expressions": "off",
"@typescript-eslint/no-throw-literal": "off"
}
}
],
"parserOptions": {
"project": "./tsconfig.json"
},
"ignorePatterns": [
"dist",
"node_modules",
".eslintrc.js",
"jest.config.js",
"functions",
"cdk.out"
]
}
116 changes: 116 additions & 0 deletions typescript/s3-sns-filter-lambda/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# Created by https://www.gitignore.io/api/osx,node,linux,windows

### Linux ###
*~
# Temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*

### Node ###
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Typescript v1 declaration files
typings/
# Optional npm cache directory
.npm
# npm list directory
target
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env

### OSX ###
*.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk

### Windows ###
# Windows thumbnail cache files
Thumbs.db
ehthumbs.db
ehthumbs_vista.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# Windows shortcuts
*.lnk

# AWS SAM and CLI directories
.aws/
.aws-sam/

# End of https://www.gitignore.io/api/osx,node,linux,windows

# Custom entries
test.ts
db.sqlite
.turbo
*.sqlite3
output
samconfig.toml
build
.vscode
cdk.out
cdk.context.json
1 change: 1 addition & 0 deletions typescript/s3-sns-filter-lambda/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cdk.out
22 changes: 22 additions & 0 deletions typescript/s3-sns-filter-lambda/.prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"printWidth": 85,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"quoteProps": "as-needed",
"jsxSingleQuote": false,
"trailingComma": "none",
"bracketSpacing": true,
"jsxBracketSameLine": false,
"arrowParens": "always",
"proseWrap": "always",
"plugins": [
"prettier-plugin-packagejson",
"@trivago/prettier-plugin-sort-imports"
],
"importOrder": ["^dotenv/config$", "<THIRD_PARTY_MODULES>", "^[./]"],
"importOrderSeparation": true,
"importOrderSortSpecifiers": true,
"importOrderCaseInsensitive": false
}
50 changes: 50 additions & 0 deletions typescript/s3-sns-filter-lambda/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# S3, SNS, Lambda Integration

This AWS CDK configuration sets up an automated workflow to trigger a specific Lambda
function based on the prefix of files uploaded to Amazon S3. Using the SNS service
with a filter policy, it directs events to the appropriate Lambda function
efficiently.

## Get Started

1. Install AWS CDK and Bootstrap Your AWS Account in a Specific Region

```
npm install -g aws-cdk
cdk bootstrap
```

2. Create a `.env` File with Your AWS Account ID

```
AWS_ACCOUNT_ID=YOUR_ACCOUNT_ID
```

3. Install Dependencies

1. Run the following command in the project root to install all dependencies:

```
yarn
```

2. Then navigate to the functions folder to install the required node modules for
Lambda functions:
```
cd ./functions yarn
```

4. Deploy to AWS

- Use this command to deploy all stacks to AWS:

```
cdk deploy --all
```

## Try it out

After running the above commands, an S3 bucket will be created. Upload a file to one
of the designated folders (e.g., folder1 or folder2). Depending on the folder, the
corresponding Lambda function (e.g., lambda1 or lambda2) will be triggered
automatically.
3 changes: 3 additions & 0 deletions typescript/s3-sns-filter-lambda/cdk.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"app": "ts-node main.ts"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"nodeEnv": "NODE_ENV",
"aws": {
"region": "AWS_REGION",
"accountId": "AWS_ACCOUNT_ID"
}
}
6 changes: 6 additions & 0 deletions typescript/s3-sns-filter-lambda/config/default.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"nodeEnv": "qa",
"aws": {
"region": "us-east-1"
}
}
3 changes: 3 additions & 0 deletions typescript/s3-sns-filter-lambda/config/develop.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"nodeEnv": "develop"
}
3 changes: 3 additions & 0 deletions typescript/s3-sns-filter-lambda/config/prod.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"nodeEnv": "production"
}
3 changes: 3 additions & 0 deletions typescript/s3-sns-filter-lambda/constants/Buckets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export enum Buckets {
ServiceBucket = 'ServiceBucket'
}
8 changes: 8 additions & 0 deletions typescript/s3-sns-filter-lambda/constants/Stacks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ResourcePrefix } from './constants';

export const Stacks = {
LambdaStack: `${ResourcePrefix}-lambda-stack`,
RoleStack: `${ResourcePrefix}-role-stack`,
StorageStack: `${ResourcePrefix}-storage-stack`,
SnsStack: `${ResourcePrefix}-sns-stack`
};
6 changes: 6 additions & 0 deletions typescript/s3-sns-filter-lambda/constants/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { config } from '../utils';

const app = 's3SnsLambda';
const { accountId } = config.aws;

export const ResourcePrefix = `${app}-${config.nodeEnv}-${accountId}`;
3 changes: 3 additions & 0 deletions typescript/s3-sns-filter-lambda/constants/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './Buckets';
export * from './constants';
export * from './Stacks';
9 changes: 9 additions & 0 deletions typescript/s3-sns-filter-lambda/functions/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "functions",
"version": "1.0.0",
"license": "ISC",
"author": "ken.yip",
"dependencies": {
"@aws-sdk/client-sns": "^3.691.0"
}
}
26 changes: 26 additions & 0 deletions typescript/s3-sns-filter-lambda/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import 'dotenv/config';

import { App, Environment } from 'aws-cdk-lib';

import { Stacks } from './constants';
import { LambdaStack, RoleStack, SnsStack, StorageStack } from './stacks';
import { config } from './utils';

const app = new App();

const env: Environment = {
account: config.aws.accountId,
region: config.aws.region
};

const roleStack = new RoleStack(app, Stacks.RoleStack, { env });
const storageStack = new StorageStack(app, Stacks.StorageStack, { env });
const snsStack = new SnsStack(app, Stacks.SnsStack, { env });

new LambdaStack(app, Stacks.LambdaStack, {
env,
serviceBucketArn: storageStack.serviceBucket.bucketArn,
s3TriggerSnsTopicArn: snsStack.s3TriggerSnsTopic.topicArn,
s3ListenerRoleArn: roleStack.s3ListenerRole.roleArn,
defaultLambdaRoleArn: roleStack.defaultLambdaRole.roleArn
});
Loading