Adding example for AWS SAM

This commit is contained in:
Enzodtz 2023-02-22 15:49:30 -03:00
parent efecce8736
commit 18ca3735ea
13 changed files with 479 additions and 0 deletions

207
examples/aws-sam/.gitignore vendored Normal file
View File

@ -0,0 +1,207 @@
# Created by https://www.toptal.com/developers/gitignore/api/osx,node,linux,windows,sam
# Edit at https://www.toptal.com/developers/gitignore?templates=osx,node,linux,windows,sam
### 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*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# 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
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
.env*.local
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
# Nuxt.js build / generate output
.nuxt
dist
# Storybook build outputs
.out
.storybook-out
storybook-static
# rollup.js default build output
dist/
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# Temporary folders
tmp/
temp/
### OSX ###
# General
.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
### SAM ###
# Ignore build directories for the AWS Serverless Application Model (SAM)
# Info: https://aws.amazon.com/serverless/sam/
# Docs: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-reference.html
**/.aws-sam
### Windows ###
# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
# Dump file
*.stackdump
# Folder config file
[Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
# Windows shortcuts
*.lnk
# End of https://www.toptal.com/developers/gitignore/api/osx,node,linux,windows,sam

View File

@ -0,0 +1,24 @@
# aws-sam-example
This project is an example of using chromium inside aws sam written from sam init Hello World template with nodeJS 16 as runtime.
### Changes from hello world template
- Installed puppeteer and @sparticuz/chromium
- Note: it must not be in dev-dependencies
- Modified the handler to instantiate the browser pointing to the AWS layer directory (`/opt/nodejs/node_modules/@sparticuz/chromium/bin`)
- Added layer in template and fixed timeout and
- Running same example as README
### Configuration
You must create a layer with the chromium binary and replace its arn inside `template.yaml`. You can see an example on how to create it in the main project README.
### Running
Build and invoke the function.
```bash
sam build
sam local invoke
```

View File

@ -0,0 +1,2 @@
node_modules
.aws-sam

View File

@ -0,0 +1,15 @@
module.exports = {
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features
sourceType: "module"
},
extends: [
"plugin:@typescript-eslint/recommended", // recommended rules from the @typescript-eslint/eslint-plugin
"plugin:prettier/recommended" // Enables eslint-plugin-prettier and eslint-config-prettier. This will display prettier errors as ESLint errors. Make sure this is always the last configuration in the extends array.
],
rules: {
// Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs
// e.g. "@typescript-eslint/explicit-function-return-type": "off",
}
};

View File

@ -0,0 +1 @@
tests/*

View File

@ -0,0 +1,7 @@
module.exports = {
semi: true,
trailingComma: "all",
singleQuote: true,
printWidth: 120,
tabWidth: 4
};

View File

@ -0,0 +1,47 @@
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
import chromium from '@sparticuz/chromium';
import puppeteer from 'puppeteer-core';
/**
*
* Event doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format
* @param {Object} event - API Gateway Lambda Proxy Input Format
*
* Return doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html
* @returns {Object} object - API Gateway Lambda Proxy Output Format
*
*/
export const lambdaHandler = async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => {
const browser = await puppeteer.launch({
args: chromium.args,
defaultViewport: chromium.defaultViewport,
executablePath: await chromium.executablePath('/opt/nodejs/node_modules/@sparticuz/chromium/bin'),
headless: chromium.headless,
ignoreHTTPSErrors: true,
});
const page = await browser.newPage();
await page.goto("https://example.com");
const pageTitle = await page.title();
await browser.close();
let response: APIGatewayProxyResult;
try {
response = {
statusCode: 200,
body: JSON.stringify({
message: pageTitle,
}),
};
} catch (err: unknown) {
console.error(err);
response = {
statusCode: 500,
body: JSON.stringify({
message: err instanceof Error ? err.message : 'some error happened',
}),
};
}
return response;
};

View File

@ -0,0 +1,15 @@
/*
* For a detailed explanation regarding each configuration property and type check, visit:
* https://jestjs.io/docs/configuration
*/
export default {
transform: {
'^.+\\.ts?$': 'esbuild-jest',
},
clearMocks: true,
collectCoverage: true,
coverageDirectory: 'coverage',
coverageProvider: 'v8',
testMatch: ['**/tests/unit/*.test.ts'],
};

View File

@ -0,0 +1,35 @@
{
"name": "hello_world",
"version": "1.0.0",
"description": "hello world sample for NodeJS",
"main": "app.js",
"repository": "https://github.com/awslabs/aws-sam-cli/tree/develop/samcli/local/init/templates/cookiecutter-aws-sam-hello-nodejs",
"author": "SAM CLI",
"license": "MIT",
"dependencies": {
"@sparticuz/chromium": "110.0.0",
"esbuild": "^0.14.14",
"puppeteer-core": "19.6.3"
},
"scripts": {
"unit": "jest",
"lint": "eslint '*.ts' --quiet --fix",
"compile": "tsc",
"test": "npm run compile && npm run unit"
},
"devDependencies": {
"@types/aws-lambda": "^8.10.92",
"@types/jest": "^27.4.0",
"@types/node": "^17.0.13",
"@typescript-eslint/eslint-plugin": "^5.10.2",
"@typescript-eslint/parser": "^5.10.2",
"esbuild-jest": "^0.5.0",
"eslint": "^8.8.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0",
"jest": "^27.5.0",
"prettier": "^2.5.1",
"ts-node": "^10.4.0",
"typescript": "^4.5.5"
}
}

View File

@ -0,0 +1,59 @@
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
import { lambdaHandler } from '../../app';
describe('Unit test for app handler', function () {
it('verifies successful response', async () => {
const event: APIGatewayProxyEvent = {
httpMethod: 'get',
body: '',
headers: {},
isBase64Encoded: false,
multiValueHeaders: {},
multiValueQueryStringParameters: {},
path: '/hello',
pathParameters: {},
queryStringParameters: {},
requestContext: {
accountId: '123456789012',
apiId: '1234',
authorizer: {},
httpMethod: 'get',
identity: {
accessKey: '',
accountId: '',
apiKey: '',
apiKeyId: '',
caller: '',
clientCert: {
clientCertPem: '',
issuerDN: '',
serialNumber: '',
subjectDN: '',
validity: { notAfter: '', notBefore: '' },
},
cognitoAuthenticationProvider: '',
cognitoAuthenticationType: '',
cognitoIdentityId: '',
cognitoIdentityPoolId: '',
principalOrgId: '',
sourceIp: '',
user: '',
userAgent: '',
userArn: '',
},
path: '/hello',
protocol: 'HTTP/1.1',
requestId: 'c6af9ac6-7b61-11e6-9a41-93e8deadbeef',
requestTimeEpoch: 1428582896000,
resourceId: '123456',
resourcePath: '/hello',
stage: 'dev',
},
resource: '',
stageVariables: {},
};
const result: APIGatewayProxyResult = await lambdaHandler(event);
expect(result.statusCode).toEqual(200);
});
});

View File

@ -0,0 +1,15 @@
{
"compilerOptions": {
"target": "es2020",
"strict": true,
"preserveConstEnums": true,
"noEmit": true,
"sourceMap": false,
"module":"es2015",
"moduleResolution":"node",
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
},
"exclude": ["node_modules", "**/*.test.ts"]
}

View File

@ -0,0 +1,52 @@
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: >
aws-sam
Sample SAM Template for aws-sam
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 90
MemorySize: 512
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
Layers:
- <YOUR_LAYER_ARN_HERE (arn:aws:lambda:...)>
CodeUri: hello-world/
Handler: app.lambdaHandler
Runtime: nodejs16.x
Architectures:
- x86_64
Events:
HelloWorld:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /hello
Method: get
Metadata: # Manage esbuild properties
BuildMethod: esbuild
BuildProperties:
Minify: true
Target: "es2020"
# Sourcemap: true # Enabling source maps will create the required NODE_OPTIONS environment variables on your lambda function during sam build
EntryPoints:
- app.ts
Outputs:
# ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
# Find out more about other implicit resources you can reference within SAM
# https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
HelloWorldApi:
Description: "API Gateway endpoint URL for Prod stage for Hello World function"
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
HelloWorldFunction:
Description: "Hello World Lambda Function ARN"
Value: !GetAtt HelloWorldFunction.Arn
HelloWorldFunctionIamRole:
Description: "Implicit IAM Role created for Hello World function"
Value: !GetAtt HelloWorldFunctionRole.Arn