-
Notifications
You must be signed in to change notification settings - Fork 966
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
New serverless pattern - apigw-websocket-api-vpclink #2391
base: main
Are you sure you want to change the base?
Changes from all commits
a2cab45
40f9e7b
ba4e67e
70f5d4d
d9e3759
458586a
43b433e
79ec4de
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
## Websocket API Gateway acknowledgement for $connect route. | ||
|
||
The SAM template deploys a websocket API Gateway and two Lambda functions required to run the application. This pattern deploys an Amazon API Gateway WebSocket API with a $connect route with a Lambda proxy integration which will invoke another Lambda function asynchronously and pass the Connection Id and the API Gateway stage URL to it. Then the Lambda function which got invoked asynchronously will check the validity of the connection. If the Connection Id is valid it will make an SDK API call to post a greeting to the client. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The explanation in first 2 lines redundant. Could you please rephrase it? |
||
|
||
Learn more about this pattern at Serverless Land Patterns: https://serverlessland.com/patterns/s3-lambda | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update the link |
||
|
||
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 for details. You are responsible for any AWS costs incurred. No warranty is implied in this example. | ||
|
||
|
||
## Requirements | ||
|
||
* [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 | ||
|
||
## 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 ack-connect-route | ||
``` | ||
3. From the command line, use AWS SAM to build and deploy the AWS resources for the pattern as specified in the template.yml file: | ||
|
||
``` | ||
sam build | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's no requirements.txt file. Do you need this command? |
||
sam deploy --guided | ||
``` | ||
4. During the prompts: | ||
* Enter a stack name | ||
* Enter the desired AWS Region | ||
* Allow SAM CLI to create IAM roles with the required permissions. | ||
|
||
Once you have run guided mode once, you can use `sam deploy` in future to use these defaults. | ||
|
||
1. Note the outputs from the SAM deployment process. These contain the resource names and/or ARNs which are used for testing. | ||
|
||
## Testing | ||
|
||
Once the application is deployed, retrieve the WebSocketURL value from CloudFormation Outputs. To test the WebSocket API, you can use [wscat](https://github.com/websockets/wscat) which is an open-source command line tool. | ||
|
||
1. [Install NPM](https://www.npmjs.com/get-npm). | ||
|
||
2. Install wscat: | ||
``` | ||
$ npm install -g wscat | ||
``` | ||
|
||
3. Connect to your WebSocketURL by executing the following command: | ||
``` | ||
$ wscat -c <YOUR WEBSOCKET URL> | ||
``` | ||
|
||
4. To test the custom route and its associated function, send a JSON-formatted request like the following example. The Lambda function sends back the value of the "data" key using the callback URL: | ||
``` | ||
$ wscat -c <YOUR WEBSOCKET URL> | ||
connected (press CTRL+C to quit) | ||
``` | ||
Comment on lines
+53
to
+62
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you kindly explain this with an example for better clarity? |
||
## Cleanup | ||
|
||
1. Delete the stack | ||
``` | ||
aws cloudformation delete-stack --stack-name <YOUR STACK NAME> | ||
``` | ||
|
||
2. Confirm the stack has been deleted | ||
``` | ||
aws cloudformation list-stacks --query "StackSummaries[?contains(StackName,'<YOUR STACK NAME>')].StackStatus" | ||
``` | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import json | ||
import boto3 | ||
|
||
lambdaClient = boto3.client('lambda') | ||
def lambda_handler(event, context): | ||
print("Got an event from some route ", event) | ||
if event['requestContext']['routeKey'] == "$connect": | ||
url = "https://" + event["requestContext"]["domainName"] + "/" + event["requestContext"]["stage"] | ||
|
||
response = lambdaClient.invoke(FunctionName="WebsocketPostToConnectionId",InvocationType="Event",Payload=json.dumps({"url": url, "connectionId":event['requestContext']['connectionId']})) | ||
payload = "This won't be received by the client" | ||
return {'statusCode': 200,'body': payload} | ||
|
||
|
||
|
||
Comment on lines
+13
to
+15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please remove extra lines here. Review all the files as well. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import json | ||
import boto3 | ||
|
||
def lambda_handler(event, context): | ||
|
||
print("Got an event from parent lambda ", event) | ||
gatewayapi = boto3.client("apigatewaymanagementapi",endpoint_url = event["url"]) | ||
response = gatewayapi.get_connection(ConnectionId=event['connectionId']) | ||
print("Response is ", response) | ||
|
||
if response["ResponseMetadata"]["HTTPStatusCode"] == 200: | ||
gatewayapi.post_to_connection(ConnectionId=event['connectionId'], Data="Hello XXX, we are now connected!! ") | ||
return {} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import json | ||
|
||
def lambda_handler(event, context): | ||
# TODO implement | ||
print("Connection has been disconnected") | ||
return { | ||
'statusCode': 200, | ||
'body': json.dumps('Hello from Lambda!') | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
AWSTemplateFormatVersion: 2010-09-09 | ||
Transform: 'AWS::Serverless-2016-10-31' | ||
Description: An Amazon API Gateway WebSocket API and an AWS Lambda function. | ||
|
||
# Global values that are applied to all applicable resources in this template | ||
Globals: | ||
Function: | ||
CodeUri: ./src | ||
Runtime: python3.12 | ||
MemorySize: 128 | ||
Timeout: 15 | ||
|
||
Resources: | ||
# API Gateway WebSocket API | ||
WebSocketApi: | ||
Type: 'AWS::ApiGatewayV2::Api' | ||
Properties: | ||
Name: !Ref AWS::StackName | ||
Description: An Amazon API Gateway WebSocket API and an AWS Lambda function. | ||
ProtocolType: WEBSOCKET | ||
RouteSelectionExpression: "$request.body.action" | ||
# Lambda Function - uses Globals to define additional configuration values | ||
OnConnectLambdaFunction: | ||
Type: 'AWS::Serverless::Function' | ||
Properties: | ||
FunctionName: !Sub '${AWS::StackName}-onconnect-function' | ||
Handler: lambda_function.lambda_handler | ||
MemorySize: 256 | ||
Policies: | ||
- Statement: | ||
- Effect: Allow | ||
Action: | ||
- 'lambda:InvokeFunction' | ||
Resource: | ||
- !Sub 'arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:WebsocketPostToConnectionId' | ||
# Function permissions grant an AWS service or another account permission to use a function | ||
OnConnectFunctionResourcePermission: | ||
Type: 'AWS::Lambda::Permission' | ||
Properties: | ||
Action: 'lambda:InvokeFunction' | ||
Principal: apigateway.amazonaws.com | ||
FunctionName: !Ref OnConnectLambdaFunction | ||
SourceArn: !Sub 'arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${WebSocketApi}/*' | ||
OnConnectIntegration: | ||
Type: AWS::ApiGatewayV2::Integration | ||
Properties: | ||
ApiId: !Ref WebSocketApi | ||
Description: OnConnect Integration | ||
IntegrationType: AWS_PROXY | ||
IntegrationUri: | ||
Fn::Sub: | ||
arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${OnConnectLambdaFunction.Arn}/invocations | ||
OnConnectRoute: | ||
Type: AWS::ApiGatewayV2::Route | ||
Properties: | ||
ApiId: !Ref WebSocketApi | ||
RouteKey: $connect | ||
AuthorizationType: NONE | ||
OperationName: OnConnectRoute | ||
Target: !Join | ||
- '/' | ||
- - 'integrations' | ||
- !Ref OnConnectIntegration | ||
# Lambda Function - uses Globals to define additional configuration values | ||
PostLambdaFunction: | ||
Type: 'AWS::Serverless::Function' | ||
Properties: | ||
FunctionName: WebsocketPostToConnectionId | ||
Handler: lambda_function_postToConnection.lambda_handler | ||
MemorySize: 256 | ||
Policies: | ||
- Statement: | ||
- Effect: Allow | ||
Action: | ||
- 'execute-api:ManageConnections' | ||
Resource: | ||
- !Sub 'arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${WebSocketApi}/*' | ||
# Function permissions grant an AWS service or another account permission to use a function | ||
|
||
OnDisconnectLambdaFunction: | ||
Type: 'AWS::Serverless::Function' | ||
Properties: | ||
FunctionName: !Sub '${AWS::StackName}-ondisconnect-function' | ||
Handler: ondisconnect.lambda_handler | ||
MemorySize: 256 | ||
# Function permissions grant an AWS service or another account permission to use a function | ||
OnDisconnectFunctionResourcePermission: | ||
Type: 'AWS::Lambda::Permission' | ||
Properties: | ||
Action: 'lambda:InvokeFunction' | ||
Principal: apigateway.amazonaws.com | ||
FunctionName: !Ref OnDisconnectLambdaFunction | ||
SourceArn: !Sub 'arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${WebSocketApi}/*' | ||
OnDisconnectIntegration: | ||
Type: AWS::ApiGatewayV2::Integration | ||
Properties: | ||
ApiId: !Ref WebSocketApi | ||
Description: OnDisconnect Integration | ||
IntegrationType: AWS_PROXY | ||
IntegrationUri: | ||
Fn::Sub: | ||
arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${OnDisconnectLambdaFunction.Arn}/invocations | ||
OnDisconnectRoute: | ||
Type: AWS::ApiGatewayV2::Route | ||
Properties: | ||
ApiId: !Ref WebSocketApi | ||
RouteKey: $disconnect | ||
AuthorizationType: NONE | ||
OperationName: OnDisconnectRoute | ||
Target: !Join | ||
- '/' | ||
- - 'integrations' | ||
- !Ref OnDisconnectIntegration | ||
Deployment: | ||
Type: AWS::ApiGatewayV2::Deployment | ||
DependsOn: | ||
- OnConnectRoute | ||
- OnDisconnectRoute | ||
Properties: | ||
ApiId: !Ref WebSocketApi | ||
Stage: | ||
Type: AWS::ApiGatewayV2::Stage | ||
Properties: | ||
StageName: prod | ||
Description: Prod Stage | ||
DeploymentId: !Ref Deployment | ||
ApiId: !Ref WebSocketApi | ||
|
||
Outputs: | ||
OnConnectLambdaFunctionArn: | ||
Description: "OnConnect function ARN" | ||
Value: !GetAtt OnConnectLambdaFunction.Arn | ||
OnDisconnectLambdaFunctionArn: | ||
Description: "OnDisconnect function ARN" | ||
Value: !GetAtt OnDisconnectLambdaFunction.Arn | ||
PostLambdaFunctionArn: | ||
Description: "Post function ARN" | ||
Value: !GetAtt PostLambdaFunction.Arn | ||
WebSocketURL: | ||
Description: "The WSS Protocol URL to connect to" | ||
Value: !Join [ '', [ 'wss://', !Ref WebSocketApi, '.execute-api.',!Ref 'AWS::Region','.amazonaws.com/',!Ref 'Stage'] ] | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
# Amazon API Gateway Websocket API with VPC Link integration | ||
|
||
The SAM template deploys an Amazon API Gateway Websocket API endpoint with a VPC Link integration. | ||
|
||
Since Websocket APIs only support VPC Links associated with NLBs (Network Load Balancers), this pattern assumes that an internal NLB already exists in a VPC in the same Region. | ||
|
||
Learn more about this pattern at Serverless Land Patterns: https://serverlessland.com/patterns/apigw-rest-api-vpclink | ||
|
||
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 for details. You are responsible for any AWS costs incurred. No warranty is implied in this example. | ||
|
||
## Requirements | ||
|
||
* [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 | ||
|
||
## 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-rest-api-vpclink | ||
``` | ||
3. From the command line, use AWS SAM to deploy the AWS resources for the pattern as specified in the template.yml file: | ||
``` | ||
sam deploy -g | ||
``` | ||
4. During the prompts: | ||
* Enter a stack name | ||
* Select the desired AWS Region | ||
* Enter the DNS name for the internal NLB (NlbInternalDns) | ||
* Enter the ARN for the internal NLB (NlbInternalArn) | ||
* Allow SAM to create roles with the required permissions if needed. | ||
|
||
Once you have run guided mode once, you can use `sam deploy` in future to use these defaults. | ||
|
||
1. Note the outputs from the SAM deployment process. These contain the resource names and/or ARNs which are used for testing. | ||
|
||
## Testing | ||
|
||
Once the application is deployed, retrieve the WebSocketURL value from CloudFormation Outputs. To test the WebSocket API, you can use [wscat](https://github.com/websockets/wscat) which is an open-source command line tool. | ||
|
||
1. [Install NPM](https://www.npmjs.com/get-npm). | ||
|
||
2. Install wscat: | ||
``` | ||
$ npm install -g wscat | ||
``` | ||
|
||
3. Connect to your WebSocketURL by executing the following command: | ||
``` | ||
$ wscat -c <YOUR WEBSOCKET URL> | ||
``` | ||
|
||
4. To test the custom route and its associated function, send a JSON-formatted request like the following example. The Lambda function sends back the value of the "data" key using the callback URL: | ||
``` | ||
$ wscat -c <YOUR WEBSOCKET URL> | ||
connected (press CTRL+C to quit) | ||
``` | ||
|
||
## Cleanup | ||
|
||
1. Delete the stack | ||
``` | ||
aws cloudformation delete-stack --stack-name <YOUR STACK NAME> | ||
``` | ||
|
||
2. Confirm the stack has been deleted | ||
``` | ||
aws cloudformation list-stacks --query "StackSummaries[?contains(StackName,'<YOUR STACK NAME>')].StackStatus" | ||
``` | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
{ | ||
"title": "Amazon API Gateway Websocket API with VPC Link integration", | ||
"description": "The SAM template deploys an Amazon API Gateway Websocket API endpoint with a VPC Link integration.", | ||
"language": "Python", | ||
"level": "200", | ||
"framework": "SAM", | ||
"gitHub": { | ||
"template": { | ||
"repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/apigw-websocket-api-vpclink", | ||
"templateURL": "serverless-patterns/apigw-websocket-api-vpclink", | ||
"projectFolder": "apigw-websocket-api-vpclink", | ||
"templateFile": "template.yaml" | ||
} | ||
}, | ||
"deploy": { | ||
"text": [ | ||
"sam deploy" | ||
] | ||
}, | ||
"testing": { | ||
"text": [ | ||
"See the GitHub repo for detailed testing instructions." | ||
] | ||
}, | ||
"cleanup": { | ||
"text": [ | ||
"Delete the stack: <code>sam delete</code>." | ||
] | ||
}, | ||
"authors": [ | ||
{ | ||
"name": "Manasvi Jain", | ||
"image": "https://avatars.githubusercontent.com/u/56217984?v=4", | ||
"bio": "Cloud Engineer at AWS", | ||
"linkedin": "https://www.linkedin.com/in/manasvi-jain-36b9941a3/" | ||
}, | ||
{ | ||
"name": "Umang Aggarwal", | ||
"image": "https://avatars.githubusercontent.com/Umang071", | ||
"bio": "Cloud Engineer II @ AWS", | ||
"linkedin": "https://www.linkedin.com/in/umangaggarwal" | ||
} | ||
] | ||
} |
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.
Please rename the folder as per the name of the pattern. You may find examples in the repository.