AWS lambda documentation change
Summary
Restructured documentation with expanded TypeScript handler guidance, added S3 integration example, project setup instructions, and best practices
Security assessment
Added example demonstrates environment variable validation (checking RECEIPT_BUCKET exists) which is a security best practice, but no specific vulnerability is addressed. The change emphasizes configuration safety rather than fixing a security flaw.
Diff
diff --git a/lambda/latest/dg/typescript-handler.md b/lambda/latest/dg/typescript-handler.md index 543cd0c19..ab6356ead 100644 --- a/lambda/latest/dg/typescript-handler.md +++ b/lambda/latest/dg/typescript-handler.md @@ -5 +5 @@ -Typescript handler basicsUsing async/awaitUsing callbacksUsing types for the event objectCode best practices for Typescript Lambda functions +Set up your projectExample functionHandler naming conventionsInput event objectValid handler patternsUsing the SDK for JavaScriptAccessing environment variablesUsing global stateBest practices @@ -11 +11 @@ The Lambda function _handler_ is the method in your function code that processes -###### Topics +This page describes how to work with Lambda function handlers in TypeScript, including options for project setup, naming conventions, and best practices. This page also includes an example of a TypeScript Lambda function that takes in information about an order, produces a text file receipt, and puts this file in an Amazon Simple Storage Service (Amazon S3) bucket. For information about how to deploy your function after writing it, see [Deploy transpiled TypeScript code in Lambda with .zip file archives](./typescript-package.html) or [Deploy transpiled TypeScript code in Lambda with container images](./typescript-image.html). @@ -13 +13 @@ The Lambda function _handler_ is the method in your function code that processes - * Typescript handler basics +###### Topics @@ -15 +15 @@ The Lambda function _handler_ is the method in your function code that processes - * Using async/await + * Setting up your TypeScript project @@ -17 +17 @@ The Lambda function _handler_ is the method in your function code that processes - * Using callbacks + * Example TypeScript Lambda function code @@ -19 +19 @@ The Lambda function _handler_ is the method in your function code that processes - * Using types for the event object + * Handler naming conventions @@ -21 +21 @@ The Lambda function _handler_ is the method in your function code that processes - * Code best practices for Typescript Lambda functions + * Defining and accessing the input event object @@ -22,0 +23 @@ The Lambda function _handler_ is the method in your function code that processes + * Valid handler patterns for TypeScript functions @@ -23,0 +25 @@ The Lambda function _handler_ is the method in your function code that processes + * Using the SDK for JavaScript v3 in your handler @@ -24,0 +27 @@ The Lambda function _handler_ is the method in your function code that processes + * Accessing environment variables @@ -26 +29 @@ The Lambda function _handler_ is the method in your function code that processes -## Typescript handler basics + * Using global state @@ -28 +31 @@ The Lambda function _handler_ is the method in your function code that processes -###### Example TypeScript handler + * Code best practices for TypeScript Lambda functions @@ -30 +32,0 @@ The Lambda function _handler_ is the method in your function code that processes -This example function logs the contents of the event object and returns the location of the logs. Note the following: @@ -32 +33,0 @@ This example function logs the contents of the event object and returns the loca - * Before using this code in a Lambda function, you must add the [@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda) package as a development dependency. This package contains the type definitions for Lambda. When `@types/aws-lambda` is installed, the `import` statement (`import ... from 'aws-lambda'`) imports the type definitions. It does not import the `aws-lambda` NPM package, which is an unrelated third-party tool. For more information, see [aws-lambda](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/aws-lambda) in the DefinitelyTyped GitHub repository. @@ -34 +34,0 @@ This example function logs the contents of the event object and returns the loca - * The handler in this example is an ES module and must be designated as such in your `package.json` file or by using the `.mjs` file extension. For more information, see see [Designating a function handler as an ES module](./lambda-nodejs.html#designate-es-module). @@ -35,0 +36 @@ This example function logs the contents of the event object and returns the loca +## Setting up your TypeScript project @@ -36,0 +38 @@ This example function logs the contents of the event object and returns the loca +Use a local integrated development environment (IDE) or text editor to write your TypeScript function code. You can’t create TypeScript code on the Lambda console. @@ -37,0 +40 @@ This example function logs the contents of the event object and returns the loca +There are multiple ways to initialize a TypeScript Lambda project. For example, you can create a project using `npm`, create an [AWS SAM application](./typescript-package.html#aws-sam-ts), or create an [AWS CDK application](./typescript-package.html#aws-cdk-ts). To create the project using `npm`: @@ -40 +43 @@ This example function logs the contents of the event object and returns the loca - import { Handler } from 'aws-lambda'; + npm init @@ -42,4 +45 @@ This example function logs the contents of the event object and returns the loca - export const handler: Handler = async (event, context) => { - console.log('EVENT: \n' + JSON.stringify(event, null, 2)); - return context.logStreamName; - }; +Your function code lives in a `.ts` file, which you transpile into a JavaScript file at build time. You can use either [esbuild](https://esbuild.github.io/) or Microsoft's TypeScript compiler (`tsc`) to transpile your TypeScript code into JavaScript. To use esbuild, add it as a development dependency: @@ -47 +46,0 @@ This example function logs the contents of the event object and returns the loca -The runtime passes arguments to the handler method. The first argument is the `event` object, which contains information from the invoker. The invoker passes this information as a JSON-formatted string when it calls [Invoke](https://docs.aws.amazon.com/lambda/latest/api/API_Invoke.html), and the runtime converts it to an object. When an AWS service invokes your function, the event structure [varies by service](./lambda-services.html). With TypeScript, we recommend using type annotations for the event object. For more information, see Using types for the event object. @@ -49 +48 @@ The runtime passes arguments to the handler method. The first argument is the `e -The second argument is the [context object](./typescript-context.html), which contains information about the invocation, function, and execution environment. In the preceding example, the function gets the name of the [log stream](./typescript-logging.html) from the context object and returns it to the invoker. + npm install -D esbuild @@ -51 +50 @@ The second argument is the [context object](./typescript-context.html), which co -You can also use a callback argument, which is a function that you can call in non-async handlers to send a response. We recommend that you use async/await instead of callbacks. Async/await provides improved readability, error handling, and efficiency. For more information about the differences between async/await and callbacks, see Using callbacks. +A typical TypeScript Lambda function project follows this general structure: @@ -53 +51,0 @@ You can also use a callback argument, which is a function that you can call in n -## Using async/await @@ -55 +53,7 @@ You can also use a callback argument, which is a function that you can call in n -If your code performs an asynchronous task, use the async/await pattern to make sure that the handler finishes running. Async/await is a concise and readable way to write asynchronous code in Node.js, without the need for nested callbacks or chaining promises. With async/await, you can write code that reads like synchronous code, while still being asynchronous and non-blocking. + /project-root + ├── index.ts - _Contains main handler_ + ├── dist/ - _Contains compiled JavaScript_ + ├── package.json - _Project metadata and dependencies_ + ├── package-lock.json - _Dependency lock file_ + ├── tsconfig.json - _TypeScript configuration_ + └── node_modules/ - _Installed dependencies_ @@ -57 +61 @@ If your code performs an asynchronous task, use the async/await pattern to make -The `async` keyword marks a function as asynchronous, and the `await` keyword pauses the execution of the function until a `Promise` is resolved. +## Example TypeScript Lambda function code @@ -59 +63 @@ The `async` keyword marks a function as asynchronous, and the `await` keyword pa -###### Example TypeScript function – asynchronous +The following example Lambda function code takes in information about an order, produces a text file receipt, and puts this file in an Amazon S3 bucket. This example defines a custom event type (`OrderEvent`). To learn how to import type definitions for AWS event sources, see [Type definitions for Lambda](./lambda-typescript.html#typescript-type-definitions). @@ -61 +65 @@ The `async` keyword marks a function as asynchronous, and the `await` keyword pa -This example uses `fetch`, which is available in the `nodejs18.x` runtime. Note the following: +###### Note @@ -63 +67 @@ This example uses `fetch`, which is available in the `nodejs18.x` runtime. Note - * Before using this code in a Lambda function, you must add the [@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda) package as a development dependency. This package contains the type definitions for Lambda. When `@types/aws-lambda` is installed, the `import` statement (`import ... from 'aws-lambda'`) imports the type definitions. It does not import the `aws-lambda` NPM package, which is an unrelated third-party tool. For more information, see [aws-lambda](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/aws-lambda) in the DefinitelyTyped GitHub repository. +This example uses an ES module handler. Lambda supports both ES module and CommonJS handlers. For more information, see [Designating a function handler as an ES module](./lambda-nodejs.html#designate-es-module). @@ -65 +69 @@ This example uses `fetch`, which is available in the `nodejs18.x` runtime. Note - * The handler in this example is an ES module and must be designated as such in your `package.json` file or by using the `.mjs` file extension. For more information, see see [Designating a function handler as an ES module](./lambda-nodejs.html#designate-es-module). +###### Example index.ts Lambda function @@ -67,0 +72 @@ This example uses `fetch`, which is available in the `nodejs18.x` runtime. Note + import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3'; @@ -68,0 +74,2 @@ This example uses `fetch`, which is available in the `nodejs18.x` runtime. Note + // Initialize the S3 client outside the handler for reuse + const s3Client = new S3Client(); @@ -69,0 +77,6 @@ This example uses `fetch`, which is available in the `nodejs18.x` runtime. Note + // Define the shape of the input event + type OrderEvent = { + order_id: string; + amount: number; + item: string; + } @@ -71,3 +84,4 @@ This example uses `fetch`, which is available in the `nodejs18.x` runtime. Note - import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda'; - const url = 'https://aws.amazon.com/'; - export const lambdaHandler = async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => { + /** + * Lambda handler for processing orders and storing receipts in S3. + */ + export const handler = async (event: OrderEvent): Promise<string> => { @@ -75,16 +89,18 @@ This example uses `fetch`, which is available in the `nodejs18.x` runtime. Note - // fetch is available with Node.js 18 - const res = await fetch(url); - return { - statusCode: res.status, - body: JSON.stringify({ - message: await res.text(), - }), - }; - } catch (err) { - console.log(err); - return { - statusCode: 500, - body: JSON.stringify({ - message: 'some error happened', - }), - }; + // Access environment variables + const bucketName = process.env.RECEIPT_BUCKET; + if (!bucketName) { + throw new Error('RECEIPT_BUCKET environment variable is not set'); + } + + // Create the receipt content and key destination + const receiptContent = `OrderID: ${event.order_id}\nAmount: $${event.amount.toFixed(2)}\nItem: ${event.item}`; + const key = `receipts/${event.order_id}.txt`; + + // Upload the receipt to S3 + await uploadReceiptToS3(bucketName, key, receiptContent); + + console.log(`Successfully processed order ${event.order_id} and stored receipt in S3 bucket ${bucketName}`); + return 'Success'; + } catch (error) { + console.error(`Failed to process order: ${error instanceof Error ? error.message : 'Unknown error'}`); + throw error; @@ -94 +110,10 @@ This example uses `fetch`, which is available in the `nodejs18.x` runtime. Note -## Using callbacks + /** + * Helper function to upload receipt to S3 + */ + async function uploadReceiptToS3(bucketName: string, key: string, receiptContent: string): Promise<void> { + try { + const command = new PutObjectCommand({ + Bucket: bucketName, + Key: key, + Body: receiptContent + }); @@ -96 +121,5 @@ This example uses `fetch`, which is available in the `nodejs18.x` runtime. Note -We recommend that you use async/await to declare the function handler instead of using callbacks. Async/await is a better choice for several reasons: + await s3Client.send(command); + } catch (error) { + throw new Error(`Failed to upload receipt to S3: ${error instanceof Error ? error.message : 'Unknown error'}`); + } + } @@ -98 +127 @@ We recommend that you use async/await to declare the function handler instead of - * **Readability:** Async/await code is easier to read and understand than callback code, which can quickly become difficult to follow and result in callback hell. +This `index.ts` file contains the following sections of code: @@ -100 +129 @@ We recommend that you use async/await to declare the function handler instead of - * **Debugging and error handling:** Debugging callback-based code can be difficult. The call stack can become hard to follow and errors can easily be swallowed. With async/await, you can use try/catch blocks to handle errors. + * `import` block: Use this block to include libraries that your Lambda function requires, such as [AWS SDK clients](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/the-request-object.html). @@ -102 +131 @@ We recommend that you use async/await to declare the function handler instead of - * **Efficiency:** Callbacks often require switching between different parts of the code. Async/await can reduce the number of context switches, resulting in more efficient code. + * `const s3Client` declaration: This initializes an [Amazon S3 client](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/s3/) outside of the handler function. This causes Lambda to run this code during the [initialization phase](./lambda-runtime-environment.html#runtimes-lifecycle-ib), and the client is preserved for [reuse across multiple invocations](./lambda-runtime-environment.html#execution-environment-reuse). @@ -103,0 +133 @@ We recommend that you use async/await to declare the function handler instead of + * `type OrderEvent`: Defines the structure of the expected input event. @@ -104,0 +135 @@ We recommend that you use async/await to declare the function handler instead of + * `export const handler`: This is the main handler function that Lambda invokes. When deploying your function, specify `index.handler` for the [Handler](https://docs.aws.amazon.com/lambda/latest/api/API_CreateFunction.html#lambda-CreateFunction-request-Handler) property. The value of the `Handler` property is the file name and the name of the exported handler method, separated by a dot. @@ -105,0 +137 @@ We recommend that you use async/await to declare the function handler instead of + * `uploadReceiptToS3` function: This is a helper function that's referenced by the main handler function. @@ -107 +138,0 @@ We recommend that you use async/await to declare the function handler instead of -When you use callbacks in your handler, the function continues to execute until the [event loop](https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/) is empty or the function times out. The response isn't sent to the invoker until all event loop tasks are finished. If the function times out, an error is returned instead. You can configure the runtime to send the response immediately by setting [context.callbackWaitsForEmptyEventLoop](./typescript-context.html) to false. @@ -109 +139,0 @@ When you use callbacks in your handler, the function continues to execute until -The callback function takes two arguments: an `Error` and a response. The response object must be compatible with `JSON.stringify`. @@ -111 +140,0 @@ The callback function takes two arguments: an `Error` and a response. The respon -###### Example TypeScript function with callback @@ -113 +142,9 @@ The callback function takes two arguments: an `Error` and a response. The respon -This sample function receives an event from Amazon API Gateway, logs the event and context objects, and then returns a response to API Gateway. Note the following: +For this function to work properly, its [ execution role](./lambda-intro-execution-role.html) must allow the `s3:PutObject` action. Also, ensure that you define the `RECEIPT_BUCKET` environment variable. After a successful invocation, the Amazon S3 bucket should contain a receipt file. + +## Handler naming conventions + +When you configure a function, the value of the [Handler](https://docs.aws.amazon.com/lambda/latest/api/API_CreateFunction.html#lambda-CreateFunction-request-Handler) setting is the file name and the name of the exported handler method, separated by a dot. The default for functions created in the console and for examples in this guide is `index.handler`. This indicates the `handler` method that's exported from the `index.js` or `index.mjs` file. + +If you create a function in the console using a different file name or function handler name, you must edit the default handler name. + +###### To change the function handler name (console) @@ -115 +152 @@ This sample function receives an event from Amazon API Gateway, logs the event a - * Before using this code in a Lambda function, you must add the [@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda) package as a development dependency. This package contains the type definitions for Lambda. When `@types/aws-lambda` is installed, the `import` statement (`import ... from 'aws-lambda'`) imports the type definitions. It does not import the `aws-lambda` NPM package, which is an unrelated third-party tool. For more information, see [aws-lambda](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/aws-lambda) in the DefinitelyTyped GitHub repository.