11import { APIGatewayProxyEvent , APIGatewayProxyResult , Context } from 'aws-lambda' ;
2- import { Metrics } from '@aws-lambda-powertools/metrics ' ;
3- import { Logger } from '@aws-lambda-powertools/logger ' ;
4- import { Tracer } from '@aws-lambda-powertools/tracer ' ;
5- import { DocumentClient } from 'aws-sdk/clients /dynamodb' ;
6-
7- // Create the PowerTools clients
8- const metrics = new Metrics ( ) ;
9- const logger = new Logger ( ) ;
10- const tracer = new Tracer ( ) ;
11-
12- // Create DynamoDB DocumentClient and patch it for tracing
13- const docClient = tracer . captureAWSClient ( new DocumentClient ( ) ) ;
14-
15- // Get the DynamoDB table name from environment variables
16- const tableName = process . env . SAMPLE_TABLE ;
2+ import { tableName } from './common/constants ' ;
3+ import { logger , tracer , metrics } from './common/powertools ' ;
4+ import { LambdaInterface } from '@aws-lambda-powertools/commons ' ;
5+ import { docClient } from './common /dynamodb-client ' ;
6+ import { GetItemCommand } from '@aws-sdk/lib-dynamodb' ;
7+ import got from 'got' ;
8+
9+ /*
10+ *
11+ * This example uses the Method decorator instrumentation.
12+ * Use TypeScript method decorators if you prefer writing your business logic using TypeScript Classes.
13+ * If you aren’t using Classes, this requires the most significant refactoring.
14+ * Find more Information in the docs: https://awslabs.github.io/aws-lambda-powertools-typescript/
15+ *
16+ */
1717
1818/**
1919 *
@@ -25,72 +25,89 @@ const tableName = process.env.SAMPLE_TABLE;
2525 *
2626 */
2727
28- export const getByIdHandler = async ( event : APIGatewayProxyEvent , context : Context ) : Promise < APIGatewayProxyResult > => {
29- if ( event . httpMethod !== 'GET' ) {
30- throw new Error ( `getById only accepts GET method, you tried: ${ event . httpMethod } ` ) ;
28+ class Lambda implements LambdaInterface {
29+
30+ @tracer . captureMethod ( )
31+ public async getUuid ( ) : Promise < string > {
32+ // Request a sample random uuid from a webservice
33+ const res = await got ( 'https://httpbin.org/uuid' ) ;
34+
35+ return JSON . parse ( res . body ) . uuid ;
3136 }
32- // Tracer: Get facade segment created by AWS Lambda
33- const segment = tracer . getSegment ( ) ;
34-
35- // Tracer: Create subsegment for the function & set it as active
36- const handlerSegment = segment . addNewSubsegment ( `## ${ process . env . _HANDLER } ` ) ;
37- tracer . setSegment ( handlerSegment ) ;
38-
39- // Tracer: Annotate the subsegment with the cold start & serviceName
40- tracer . annotateColdStart ( ) ;
41- tracer . addServiceNameAnnotation ( ) ;
42-
43- // Tracer: Add annotation for the awsRequestId
44- tracer . putAnnotation ( 'awsRequestId' , context . awsRequestId ) ;
45-
46- // Metrics: Capture cold start metrics
47- metrics . captureColdStartMetric ( ) ;
48-
49- // Logger: Add persistent attributes to each log statement
50- logger . addPersistentLogAttributes ( {
51- awsRequestId : context . awsRequestId ,
52- } ) ;
53-
54- // Get the item from the table
55- // https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html#get-property
56- let response ;
57- try {
58- if ( ! tableName ) {
59- throw new Error ( 'SAMPLE_TABLE environment variable is not set' ) ;
60- }
61- if ( ! event . pathParameters ) {
62- throw new Error ( 'event does not contain pathParameters' ) ;
63- }
64- if ( ! event . pathParameters . id ) {
65- throw new Error ( 'PathParameter id is missing' ) ;
37+
38+ @tracer . captureLambdaHandler ( { captureResponse : false } ) // by default the tracer would add the response as metadata on the segment, but there is a chance to hit the 64kb segment size limit. Therefore set captureResponse: false
39+ @logger . injectLambdaContext ( { logEvent : true } )
40+ @metrics . logMetrics ( { throwOnEmptyMetrics : false , captureColdStartMetric : true } )
41+ public async handler ( event : APIGatewayProxyEvent , context : Context ) : Promise < APIGatewayProxyResult > {
42+
43+ if ( event . httpMethod !== 'GET' ) {
44+ throw new Error ( `getById only accepts GET method, you tried: ${ event . httpMethod } ` ) ;
6645 }
6746
68- const data = await docClient . get ( {
69- TableName : tableName ,
70- Key : { id : event . pathParameters . id } ,
71- } ) . promise ( ) ;
72- const item = data . Item ;
73- response = {
74- statusCode : 200 ,
75- body : JSON . stringify ( item )
76- } ;
77- } catch ( err ) {
78- tracer . addErrorAsMetadata ( err as Error ) ;
79- logger . error ( 'Error reading from table. ' + err ) ;
80- response = {
81- statusCode : 500 ,
82- body : JSON . stringify ( { 'error' : 'Error reading from table.' } )
83- } ;
84- }
47+ // Tracer: Add awsRequestId as annotation
48+ tracer . putAnnotation ( 'awsRequestId' , context . awsRequestId ) ;
49+
50+ // Logger: Append awsRequestId to each log statement
51+ logger . appendKeys ( {
52+ awsRequestId : context . awsRequestId ,
53+ } ) ;
54+
55+ // Call the getUuid function
56+ const uuid = await this . getUuid ( ) ;
57+
58+ // Logger: Append uuid to each log statement
59+ logger . appendKeys ( { uuid } ) ;
60+
61+ // Tracer: Add uuid as annotation
62+ tracer . putAnnotation ( 'uuid' , uuid ) ;
63+
64+ // Metrics: Add uuid as metadata
65+ metrics . addMetadata ( 'uuid' , uuid ) ;
66+
67+ // Define response object
68+ let response ;
69+
70+ // Get the item from the table
71+ // https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html#get-property
72+ try {
73+ if ( ! tableName ) {
74+ throw new Error ( 'SAMPLE_TABLE environment variable is not set' ) ;
75+ }
76+ if ( ! event . pathParameters ) {
77+ throw new Error ( 'event does not contain pathParameters' ) ;
78+ }
79+ if ( ! event . pathParameters . id ) {
80+ throw new Error ( 'PathParameter id is missing' ) ;
81+ }
82+ const data = await docClient . send ( new GetItemCommand ( {
83+ TableName : tableName ,
84+ Key : { id :
85+ {
86+ S : event . pathParameters . id
87+ }
88+ } ,
89+ } ) ) ;
90+ const item = data . Item ;
91+ response = {
92+ statusCode : 200 ,
93+ body : JSON . stringify ( item )
94+ } ;
95+ } catch ( err ) {
96+ tracer . addErrorAsMetadata ( err as Error ) ;
97+ logger . error ( 'Error reading from table. ' + err ) ;
98+ response = {
99+ statusCode : 500 ,
100+ body : JSON . stringify ( { 'error' : 'Error reading from table.' } )
101+ } ;
102+ }
85103
86- // Tracer: Close subsegment (the AWS Lambda one is closed automatically)
87- handlerSegment . close ( ) ; // (## index.handler)
104+ // All log statements are written to CloudWatch
105+ logger . info ( `response from: ${ event . path } statusCode: ${ response . statusCode } body: ${ response . body } ` ) ;
88106
89- // Tracer: Set the facade segment as active again (the one created by AWS Lambda)
90- tracer . setSegment ( segment ) ;
107+ return response ;
108+ }
91109
92- // All log statements are written to CloudWatch
93- logger . info ( `response from: ${ event . path } statusCode: ${ response . statusCode } body: ${ response . body } ` ) ;
110+ }
94111
95- return response ;
96- } ;
112+ const handlerClass = new Lambda ( ) ;
113+ export const handler = handlerClass . handler . bind ( handlerClass ) ;
0 commit comments