-
Notifications
You must be signed in to change notification settings - Fork 156
docs(examples): add example for AWS SAM #674
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 18 commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
01324a8
added example for AWS SAM
9c3d999
removed unnecessary hello-world folder
ed0abd2
tsconfig now in line with other tsconfigs in this repo
fd6acbc
added try/catch block + metric annotation + error logging for dynamod…
644a76a
Importing only DynamoDB instead of whole aws-sdk. Patching only the D…
58a3ca4
removed prettier; aligned dependency versions with others in this repo
ef8239a
Update examples/sam/README.md
bpauwels cf2f9c6
Update examples/sam/README.md
bpauwels 8ce19c7
Merge branch 'awslabs:main' into examples-sam
bpauwels cb28daf
seperated lambda function code
5266452
Updated README.md
007c990
Updated README.md removed powertools example folder
f6bc21c
Updated README.md changed cleanup to sam delete
caf39e2
fixed eslint issues
b6953dc
added copied files to .gitignore
d5969b8
multiple changes to template.yaml
a35bb80
changed policy to DynamoDBReadPolicy for all get* Lambdas
7a355cf
fixed escaped DynamodDB description in template.yaml
5fd51c6
fixed README.md; changed try catch to capture missing env; import onl…
17831a3
fixed tracer.captureAWSClient to capture DocumentClient
3b68bdb
moved package.json to sam folder
de14ec6
changed author in package.json; various changes to README.md; changed…
48425c0
removed redundant comments
6b55f2d
added additional steps to readme.md
310c39f
removed null assertions
ae2dddf
removed manual copy step and created a symlink instead
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda'; | ||
import { Metrics } from '@aws-lambda-powertools/metrics'; | ||
import { Logger } from '@aws-lambda-powertools/logger'; | ||
import { Tracer } from '@aws-lambda-powertools/tracer'; | ||
import { DynamoDB } from 'aws-sdk'; | ||
bpauwels marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// Create the PowerTools clients | ||
const metrics = new Metrics(); | ||
const logger = new Logger(); | ||
const tracer = new Tracer(); | ||
|
||
// Create DynamoDB DocumentClient and patch it for tracing | ||
const docClient = tracer.captureAWS(new DynamoDB.DocumentClient()); | ||
bpauwels marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// Get the DynamoDB table name from environment variables | ||
const tableName = process.env.SAMPLE_TABLE; | ||
|
||
/** | ||
* | ||
* 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 getAllItemsHandler = async (event: APIGatewayProxyEvent, context: Context): Promise<APIGatewayProxyResult> => { | ||
if (event.httpMethod !== 'GET') { | ||
throw new Error(`getAllItems only accepts GET method, you tried: ${event.httpMethod}`); | ||
} | ||
// Tracer: Get facade segment created by AWS Lambda | ||
const segment = tracer.getSegment(); | ||
|
||
// Tracer: Create subsegment for the function & set it as active | ||
const handlerSegment = segment.addNewSubsegment(`## ${process.env._HANDLER}`); | ||
tracer.setSegment(handlerSegment); | ||
|
||
// Tracer: Annotate the subsegment with the cold start & serviceName | ||
tracer.annotateColdStart(); | ||
tracer.addServiceNameAnnotation(); | ||
|
||
// Tracer: Add annotation for the awsRequestId | ||
tracer.putAnnotation('awsRequestId', context.awsRequestId); | ||
|
||
// Metrics: Capture cold start metrics | ||
metrics.captureColdStartMetric(); | ||
|
||
// All log statements are written to CloudWatch | ||
logger.debug('received:', event); | ||
bpauwels marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// get all items from the table (only first 1MB data, you can use `LastEvaluatedKey` to get the rest of data) | ||
// https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html#scan-property | ||
// https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Scan.html | ||
const params = { | ||
TableName: tableName! | ||
bpauwels marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}; | ||
|
||
let response; | ||
|
||
try { | ||
const data = await docClient.scan(params).promise(); | ||
const items = data.Items; | ||
response = { | ||
statusCode: 200, | ||
body: JSON.stringify(items) | ||
}; | ||
} catch (err) { | ||
tracer.addErrorAsMetadata(err as Error); | ||
logger.error('Error reading from table. ' + err); | ||
response = { | ||
statusCode: 500, | ||
body: JSON.stringify({ 'error': 'Error reading from table.' }) | ||
}; | ||
} | ||
|
||
// Tracer: Close subsegment (the AWS Lambda one is closed automatically) | ||
handlerSegment.close(); // (## index.handler) | ||
|
||
// Tracer: Set the facade segment as active again (the one created by AWS Lambda) | ||
tracer.setSegment(segment); | ||
|
||
// All log statements are written to CloudWatch | ||
logger.info(`response from: ${event.path} statusCode: ${response.statusCode} body: ${response.body}`); | ||
|
||
return response; | ||
}; | ||
bpauwels marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda'; | ||
import { Metrics } from '@aws-lambda-powertools/metrics'; | ||
import { Logger } from '@aws-lambda-powertools/logger'; | ||
import { Tracer } from '@aws-lambda-powertools/tracer'; | ||
import { DynamoDB } from 'aws-sdk'; | ||
bpauwels marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// Create the PowerTools clients | ||
const metrics = new Metrics(); | ||
const logger = new Logger(); | ||
const tracer = new Tracer(); | ||
|
||
// Create DynamoDB DocumentClient and patch it for tracing | ||
const docClient = tracer.captureAWS(new DynamoDB.DocumentClient()); | ||
|
||
// Get the DynamoDB table name from environment variables | ||
const tableName = process.env.SAMPLE_TABLE; | ||
|
||
/** | ||
* | ||
* 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 getByIdHandler = async (event: APIGatewayProxyEvent, context: Context): Promise<APIGatewayProxyResult> => { | ||
if (event.httpMethod !== 'GET') { | ||
throw new Error(`getById only accepts GET method, you tried: ${event.httpMethod}`); | ||
} | ||
// Tracer: Get facade segment created by AWS Lambda | ||
const segment = tracer.getSegment(); | ||
|
||
// Tracer: Create subsegment for the function & set it as active | ||
const handlerSegment = segment.addNewSubsegment(`## ${process.env._HANDLER}`); | ||
tracer.setSegment(handlerSegment); | ||
|
||
// Tracer: Annotate the subsegment with the cold start & serviceName | ||
tracer.annotateColdStart(); | ||
tracer.addServiceNameAnnotation(); | ||
|
||
// Tracer: Add annotation for the awsRequestId | ||
tracer.putAnnotation('awsRequestId', context.awsRequestId); | ||
|
||
// Metrics: Capture cold start metrics | ||
metrics.captureColdStartMetric(); | ||
|
||
// All log statements are written to CloudWatch | ||
logger.debug('received:', event); | ||
|
||
// Get id from pathParameters from APIGateway because of `/{id}` at template.yaml | ||
const id = event.pathParameters!.id; | ||
bpauwels marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// Get the item from the table | ||
// https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html#get-property | ||
const params = { | ||
TableName: tableName!, | ||
Key: { id: id }, | ||
}; | ||
|
||
let response; | ||
|
||
try { | ||
const data = await docClient.get(params).promise(); | ||
const item = data.Item; | ||
response = { | ||
statusCode: 200, | ||
body: JSON.stringify(item) | ||
}; | ||
} catch (err) { | ||
tracer.addErrorAsMetadata(err as Error); | ||
logger.error('Error reading from table. ' + err); | ||
response = { | ||
statusCode: 500, | ||
body: JSON.stringify({ 'error': 'Error reading from table.' }) | ||
}; | ||
} | ||
|
||
// Tracer: Close subsegment (the AWS Lambda one is closed automatically) | ||
handlerSegment.close(); // (## index.handler) | ||
|
||
// Tracer: Set the facade segment as active again (the one created by AWS Lambda) | ||
tracer.setSegment(segment); | ||
|
||
// All log statements are written to CloudWatch | ||
logger.info(`response from: ${event.path} statusCode: ${response.statusCode} body: ${response.body}`); | ||
|
||
return response; | ||
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
{ | ||
"name": "hello_world", | ||
"version": "1.0.0", | ||
"description": "AWS Lambda Powertools for TypeScript Sample", | ||
"author": "SAM CLI", | ||
bpauwels marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"license": "MIT", | ||
"dependencies": { | ||
"@aws-lambda-powertools/logger": "^0.7.0", | ||
"@aws-lambda-powertools/metrics": "^0.7.0", | ||
"@aws-lambda-powertools/tracer": "^0.7.0" | ||
}, | ||
"scripts": { | ||
"lint": "eslint '*.ts' --quiet --fix", | ||
"compile": "tsc" | ||
}, | ||
"devDependencies": { | ||
"@types/aws-lambda": "^8.10.86", | ||
"@types/node": "17.0.10", | ||
"@typescript-eslint/parser": "^5.12.1", | ||
"esbuild": "^0.14.23", | ||
"eslint": "^8.4.0", | ||
"ts-node": "^10.0.0", | ||
"typescript": "^4.1.3" | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda'; | ||
import { Metrics } from '@aws-lambda-powertools/metrics'; | ||
import { Logger } from '@aws-lambda-powertools/logger'; | ||
import { Tracer } from '@aws-lambda-powertools/tracer'; | ||
import { DynamoDB } from 'aws-sdk'; | ||
bpauwels marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// Create the PowerTools clients | ||
const metrics = new Metrics(); | ||
const logger = new Logger(); | ||
const tracer = new Tracer(); | ||
|
||
// Create DynamoDB DocumentClient and patch it for tracing | ||
const docClient = tracer.captureAWS(new DynamoDB.DocumentClient()); | ||
|
||
// Get the DynamoDB table name from environment variables | ||
const tableName = process.env.SAMPLE_TABLE; | ||
|
||
/** | ||
* | ||
* 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 putItemHandler = async (event: APIGatewayProxyEvent, context: Context): Promise<APIGatewayProxyResult> => { | ||
if (event.httpMethod !== 'POST') { | ||
throw new Error(`putItem only accepts POST method, you tried: ${event.httpMethod}`); | ||
} | ||
// Tracer: Get facade segment created by AWS Lambda | ||
const segment = tracer.getSegment(); | ||
|
||
// Tracer: Create subsegment for the function & set it as active | ||
const handlerSegment = segment.addNewSubsegment(`## ${process.env._HANDLER}`); | ||
tracer.setSegment(handlerSegment); | ||
|
||
// Tracer: Annotate the subsegment with the cold start & serviceName | ||
tracer.annotateColdStart(); | ||
tracer.addServiceNameAnnotation(); | ||
|
||
// Tracer: Add annotation for the awsRequestId | ||
tracer.putAnnotation('awsRequestId', context.awsRequestId); | ||
|
||
// Metrics: Capture cold start metrics | ||
metrics.captureColdStartMetric(); | ||
|
||
// All log statements are written to CloudWatch | ||
logger.debug('received:', event); | ||
|
||
// Get id and name from the body of the request | ||
const body = JSON.parse(event.body!); | ||
bpauwels marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const id = body.id; | ||
const name = body.name; | ||
|
||
// Creates a new item, or replaces an old item with a new item | ||
// https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html#put-property | ||
const params = { | ||
TableName: tableName!, | ||
Item: { id: id, name: name } | ||
}; | ||
|
||
let response; | ||
|
||
try { | ||
await docClient.put(params).promise(); | ||
response = { | ||
statusCode: 200, | ||
body: JSON.stringify(body) | ||
}; | ||
} catch (err) { | ||
tracer.addErrorAsMetadata(err as Error); | ||
logger.error('Error writing data to table. ' + err); | ||
response = { | ||
statusCode: 500, | ||
body: JSON.stringify({ 'error': 'Error writing data to table.' }) | ||
}; | ||
} | ||
|
||
// Tracer: Close subsegment (the AWS Lambda one is closed automatically) | ||
handlerSegment.close(); // (## index.handler) | ||
|
||
// Tracer: Set the facade segment as active again (the one created by AWS Lambda) | ||
tracer.setSegment(segment); | ||
|
||
// All log statements are written to CloudWatch | ||
logger.info(`response from: ${event.path} statusCode: ${response.statusCode} body: ${response.body}`); | ||
|
||
return response; | ||
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
{ | ||
"compilerOptions": { | ||
"experimentalDecorators": true, | ||
"noImplicitAny": true, | ||
"target": "ES2020", | ||
"module": "commonjs", | ||
"declaration": true, | ||
"declarationMap": true, | ||
"outDir": "lib", | ||
"removeComments": false, | ||
"strict": true, | ||
"inlineSourceMap": true, | ||
"moduleResolution": "node", | ||
"resolveJsonModule": true, | ||
"pretty": true, | ||
"esModuleInterop": true | ||
}, | ||
"exclude": [ "./node_modules"], | ||
"watchOptions": { | ||
"watchFile": "useFsEvents", | ||
"watchDirectory": "useFsEvents", | ||
"fallbackPolling": "dynamicPriority" | ||
}, | ||
"lib": [ "es2020" ], | ||
"types": [ | ||
"node" | ||
] | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.