-
Notifications
You must be signed in to change notification settings - Fork 997
New serverless pattern - appsync websockets with lambda and bedrock #2773
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
julianwood
merged 5 commits into
aws-samples:main
from
humem001:mjhume-appsync-ws-lambda-bedrock-sam
Jul 23, 2025
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
c36f3cb
apigw websockets with lambda and bedrock
humem001 22fb89a
appsync websockets with lambda and bedrock
humem001 91fec30
Merge branch 'aws-samples:main' into mjhume-appsync-ws-lambda-bedrock…
humem001 8a71790
appsync websockets with lambda and bedrock updated readme
humem001 6fff67d
Create appsync-ws-lambda-bedrock-sam.json
marakere 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
node_modules/ | ||
.aws-sam/ |
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,109 @@ | ||
# AI Chat Application using Amazon API Gateway (WebSockets), AWS Lambda, and Amazon Bedrock. | ||
|
||
This serverless architecture enables real-time AI chat using AWS services. A WebSocket Amazon API Gateway maintains persistent connections between clients and a Node.js AWS Lambda function. The AWS Lambda function handles user connections/disconnections, stores connection IDs in Amazon DynamoDB, and processes messages through an Amazon Bedrock LLM. The system includes error handling, automatic scaling, and pay-per-use pricing. The AWS SAM template provisions all necessary resources and IAM permissions, outputting a WebSocket URL for client connections. | ||
|
||
|
||
Learn more about this pattern at [Serverless Land Patterns](https://serverlessland.com/patterns/apigw-websockets-lambda-bedrock-sam) | ||
|
||
Important: this application uses various AWS services and there are costs associated with these services after the Free Tier usage - please see the [AWS Pricing page](https://aws.amazon.com/pricing/) for details. You are responsible for any AWS costs incurred. No warranty is implied in this example. | ||
|
||
## Prerequisites | ||
|
||
* [Create an AWS account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html) if you do not already have one and log in. The IAM user that you use must have sufficient permissions to make necessary AWS service calls and manage AWS resources. | ||
* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed and configured | ||
* [Git Installed](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) | ||
* [AWS Serverless Application Model](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) (AWS SAM) installed | ||
* [NOTE! Manage Access to Amazon Bedrock Foundation Models](https://docs.aws.amazon.com/bedrock/latest/userguide/model-access.html) | ||
|
||
|
||
## Deployment Instructions | ||
1. Create a new directory, navigate to that directory in a terminal and clone the GitHub repository: | ||
``` | ||
git clone https://github.com/aws-samples/serverless-patterns | ||
``` | ||
2. Change directory to the pattern directory: | ||
``` | ||
cd apigw-websockets-lambda-bedrock-sam | ||
``` | ||
3. Install dependencies | ||
``` | ||
cd src && npm install && cd .. | ||
``` | ||
4. From the command line, use AWS SAM build to prepare an application for subsequent steps in the developer workflow, such as local testing or deploying to the AWS Cloud: | ||
``` | ||
sam build | ||
``` | ||
5. From the command line, use AWS SAM to deploy the AWS resources for the pattern as specified in the template.yml file: | ||
``` | ||
sam deploy --guided | ||
``` | ||
6. During the prompts: | ||
* Enter a stack name | ||
* Enter the desired AWS Region | ||
* Enter the desired BedrockRegion | ||
* Enter the desired BedrockModelId | ||
* Allow SAM to create roles with the required permissions if needed. | ||
|
||
7. Note the outputs **WebSocket URL** from the SAM deployment process. | ||
These contain the resource names and/or ARNs which are used for testing. | ||
```bash | ||
wss://<YOUR-WebSocket-URL>.execute-api.<YOUR-AWS-Region>.amazonaws.com/prod | ||
``` | ||
|
||
## Architecture | ||
 | ||
|
||
|
||
## How it Works | ||
WebSocket API Gateway serves as the entry point, enabling bidirectional real-time communication between clients and the backend. It handles three routes: | ||
* $connect - when users join the chat | ||
* $disconnect - when users leave | ||
* $default - for processing chat messages | ||
|
||
Lambda Function (Node.js 22.x) acts as the central orchestrator, handling all WebSocket events and business logic. It manages connection lifecycle, processes user messages, and coordinates with other AWS services. | ||
DynamoDB Table stores active WebSocket connection IDs, enabling the system to track which users are currently connected and send responses back to the correct clients. | ||
Amazon Bedrock provides AI capabilities using Claude 3 Sonnet model, processing user messages and generating intelligent responses. | ||
|
||
Data Flow: | ||
1. Connection: When a user connects, their connection ID is stored in DynamoDB | ||
2. Message Processing: User sends a message through WebSocket → Lambda receives it → Extracts message content → Sends to Bedrock Claude model | ||
3. AI Response: Bedrock processes the message and returns an AI-generated response | ||
4. Real-time Delivery: Lambda sends the AI response back to the user via WebSocket connection | ||
5. Disconnection: When user disconnects, their connection ID is removed from DynamoDB | ||
|
||
## Testing | ||
|
||
### Interactive Web Interface | ||
``` | ||
To use the test interface: | ||
1. Deploy the application using SAM | ||
2. Copy the WebSocket URL from the deployment outputs | ||
3. Open 'test.html' and update the 'WS_URL' variable with your WebSocket URL and AWS Region | ||
wss://<YOUR-WebSocket-URL>.execute-api.<YOUR-AWS-Region>.amazonaws.com/prod | ||
4. Save 'test.html' | ||
5. Open the HTML file in a browser | ||
6. Click "Connect" to establish a WebSocket connection | ||
7. Type your message and click "Send" | ||
8. When complete Click "Disconnect" | ||
``` | ||
|
||
### Command Line (wscat) | ||
```bash | ||
npm install -g wscat | ||
wscat -c wss://your-api-id.execute-api.your-region.amazonaws.com/prod | ||
# Then send: {"data": "What is AWS Lambda?"} | ||
``` | ||
|
||
## Cleanup | ||
1. Delete the stack | ||
```bash | ||
sam delete | ||
``` | ||
2. Confirm the stack has been deleted | ||
```bash | ||
aws cloudformation list-stacks --query "StackSummaries[?contains(StackName,'STACK_NAME')].StackStatus" | ||
``` | ||
---- | ||
Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
|
||
SPDX-License-Identifier: MIT-0 |
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,70 @@ | ||
{ | ||
"title": "AI Chat with Amazon API Gateway (WebSockets), AWS Lambda, and Amazon Bedrock.", | ||
|
||
"description": "WebSocket-Enabled AI Chat Using AWS Services.", | ||
|
||
"language": "", | ||
"level": "200", | ||
"framework": "SAM", | ||
"introBox": { | ||
"headline": "How it works", | ||
"text": [ | ||
"This serverless architecture enables real-time AI chat using AWS services. A WebSocket Amazon API Gateway maintains persistent connections between clients and a Node.js AWS Lambda function.", | ||
"The AWS Lambda function handles user connections/disconnections, stores connection IDs in Amazon DynamoDB, and processes messages through an Amazon Bedrock LLM.", | ||
"The system includes error handling, automatic scaling, and pay-per-use pricing.", | ||
"The AWS SAM template provisions all necessary resources and IAM permissions, outputting a WebSocket URL for client connections." | ||
] | ||
}, | ||
"gitHub": { | ||
"template": { | ||
"repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/apigw-websockets-lambda-bedrock-sam", | ||
"templateURL": "serverless-patterns/apigw-websockets-lambda-bedrock-sam", | ||
"projectFolder": "apigw-websockets-lambda-bedrock-sam", | ||
"templateFile": "template.yml" | ||
} | ||
}, | ||
"resources": { | ||
"bullets": [ | ||
{ | ||
"text": "Amazon API Gateway", | ||
"link": "https://aws.amazon.com/api-gateway/" | ||
}, | ||
{ | ||
"text": "Amazon API Gateway WebSocket APIs", | ||
"link": "https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api.html" | ||
}, | ||
{ | ||
"text": "AWS Lambda", | ||
"link": "https://aws.amazon.com/lambda/" | ||
}, | ||
{ | ||
"text": "Amazon Bedrock", | ||
"link": "https://aws.amazon.com/bedrock/" | ||
} | ||
] | ||
}, | ||
"deploy": { | ||
"text": [ | ||
"sam deploy" | ||
] | ||
}, | ||
"testing": { | ||
"text": [ | ||
"See the GitHub repo for detailed testing instructions." | ||
] | ||
}, | ||
"cleanup": { | ||
"text": [ | ||
"<code>sam delete</code>" | ||
] | ||
}, | ||
"authors": [ | ||
{ | ||
"name": "Mike Hume", | ||
"image": "https://media.licdn.com/dms/image/D4E03AQEiUfmBiUOw_A/profile-displayphoto-shrink_200_200/0/1718324029612?e=1727308800&v=beta&t=ybhm76l-CP5xcUsHbdq2IaJOlfyycvQ6gNwuCSd3Z0w", | ||
"bio": "AWS Senior Solutions Architect & UKPS Serverless Lead.", | ||
"linkedin": "michael-hume-4663bb64", | ||
"twitter": "" | ||
} | ||
] | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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,79 @@ | ||
import { DynamoDBClient } from '@aws-sdk/client-dynamodb'; | ||
import { DynamoDBDocumentClient, PutCommand, DeleteCommand } from '@aws-sdk/lib-dynamodb'; | ||
import { ApiGatewayManagementApiClient, PostToConnectionCommand } from '@aws-sdk/client-apigatewaymanagementapi'; | ||
import { BedrockRuntimeClient, InvokeModelCommand } from '@aws-sdk/client-bedrock-runtime'; | ||
|
||
const ddbClient = new DynamoDBClient({}); | ||
const ddb = DynamoDBDocumentClient.from(ddbClient); | ||
// Bedrock client using region from environment variable | ||
const bedrock = new BedrockRuntimeClient({ region: process.env.BEDROCK_REGION }); | ||
|
||
export const handler = async (event) => { | ||
const { routeKey, connectionId } = event.requestContext; | ||
const tableName = process.env.CONNECTIONS_TABLE; | ||
|
||
try { | ||
switch (routeKey) { | ||
case '$connect': | ||
await ddb.send(new PutCommand({ | ||
TableName: tableName, | ||
Item: { connectionId } | ||
})); | ||
return { statusCode: 200 }; | ||
|
||
case '$disconnect': | ||
await ddb.send(new DeleteCommand({ | ||
TableName: tableName, | ||
Key: { connectionId } | ||
})); | ||
return { statusCode: 200 }; | ||
|
||
case '$default': | ||
const message = JSON.parse(event.body || '{}'); | ||
const userMessage = message.data || 'Hello'; | ||
|
||
const apiGw = new ApiGatewayManagementApiClient({ | ||
endpoint: `https://${event.requestContext.domainName}/${event.requestContext.stage}` | ||
}); | ||
|
||
try { | ||
// Invoke Bedrock Claude model | ||
const bedrockResponse = await bedrock.send(new InvokeModelCommand({ | ||
modelId: process.env.BEDROCK_MODEL_ID, | ||
body: JSON.stringify({ | ||
anthropic_version: 'bedrock-2023-05-31', | ||
max_tokens: 1000, | ||
messages: [{ | ||
role: 'user', | ||
content: userMessage | ||
}] | ||
}) | ||
})); | ||
|
||
const responseBody = JSON.parse(new TextDecoder().decode(bedrockResponse.body)); | ||
const aiResponse = responseBody.content[0].text; | ||
|
||
await apiGw.send(new PostToConnectionCommand({ | ||
ConnectionId: connectionId, | ||
Data: JSON.stringify({ message: aiResponse }) | ||
})); | ||
} catch (bedrockError) { | ||
console.error('Bedrock error:', bedrockError); | ||
await apiGw.send(new PostToConnectionCommand({ | ||
ConnectionId: connectionId, | ||
Data: JSON.stringify({ | ||
message: `Sorry, I'm having trouble connecting to the AI service. Please try again in a moment.` | ||
}) | ||
})); | ||
} | ||
|
||
return { statusCode: 200 }; | ||
|
||
default: | ||
return { statusCode: 400, body: 'Unknown route' }; | ||
} | ||
} catch (error) { | ||
console.error('Error:', error); | ||
return { statusCode: 500, body: JSON.stringify({ error: error.message }) }; | ||
} | ||
}; |
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,11 @@ | ||
{ | ||
"name": "websocket-handler", | ||
"version": "1.0.0", | ||
"type": "module", | ||
"dependencies": { | ||
"@aws-sdk/client-dynamodb": "^3.0.0", | ||
"@aws-sdk/lib-dynamodb": "^3.0.0", | ||
"@aws-sdk/client-apigatewaymanagementapi": "^3.0.0", | ||
"@aws-sdk/client-bedrock-runtime": "^3.0.0" | ||
} | ||
} |
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update this command to cd to lambda and run npm