Real-Time Communication with AWS API Gateway WebSockets and Lambda
August 2, 2024WebSockets have revolutionized the way we build interactive, real-time web applications.
Unlike traditional HTTP requests, WebSockets enable bidirectional communication between clients and servers, allowing for instant data exchange without the need for constant polling.
This technology is particularly useful for applications like chat systems, live updates, collaborative tools, and online gaming.
AWS has embraced this powerful technology by integrating WebSocket support into its API Gateway service, coupled with the serverless capabilities of AWS Lambda. This combination allows developers to create scalable, real-time applications with ease.
What are WebSockets?
WebSockets are a communication protocol that enables full-duplex, bidirectional communication between a client (such as a web browser) and a server over a single, long-lived connection.
Unlike traditional HTTP requests, which are one-way and require the client to repeatedly poll the server for updates, WebSockets allow both the client and server to send and receive messages in real time.
This makes WebSockets ideal for applications that need instant data exchange.
How WebSockets work on AWS
AWS API Gateway’s WebSocket APIs provide a managed service for handling WebSocket connections.
Here’s how it works:
- Connection Establishment - When a client initiates a WebSocket connection, API Gateway invokes a Lambda function associated with the $connect route. This function can perform tasks such as authentication and storing connection information.
- Disconnection - When a client disconnects, API Gateway triggers the Lambda function associated with the $disconnect route, allowing for cleanup operations.
- Message Handling - Once connected, clients can send messages to the server. API Gateway uses a route selection expression to determine which Lambda function to invoke based on the message content.
- Server Push - Unlike traditional HTTP APIs, WebSocket APIs allow the server to push messages to connected clients. This is done using the API Gateway Management API, which can be called from Lambda functions.
Example:
In this example, you’ll see how to implement WebSockets using CDK.
We’ve created a very simple chat application. By following the deployment steps, you should be able to chat between terminals.
Once deployed, your application will have the following architecture:
After deployment, use the WebSocketUrl from the deployed stack to start chatting!
npx cdk deploy
...
...
...
Outputs:
WebsocketsStack.WebSocketUrl = wss://<ID>.execute-api.<REGION>.amazonaws.com/<STAGE>
First, open a new terminal and connect to the WebSocket. Then, you can send a message to the connection.
This message contains only an action whoAmI
, which is used to route to the correct Lambda function.
Once the whoAmI
-Lambda function is successfully invoked, it will return the connectionId
of this terminal.
geri@superluminar terminal-1 % websocat <WebsocketsStack.WebSocketUrl>
{"action": "whoAmI"}
btvXRd6dliACF-A=
In the second terminal, connect as well, but use the action sendMessage
, along with the connectionId
from the first terminal and a message
to send to terminal 1.
For example, a simple Hi! :)
will do.
geri@superluminar terminal-2 % websocat <WebsocketsStack.WebSocketUrl>
{"action": "sendMessage", "connectionId": "btvXRd6dliACF-A=", "message": "Hi! :)"}
If everything worked out, you should see your message from Terminal 1
in Terminal 2
!
🎉 🎉 🎉 🎉 🎉
geri@superluminar terminal-1 % websocat <WebsocketsStack.WebSocketUrl>
{"action": "whoAmI"}
btvXRd6dliACF-A=
Hi! :)
You can now continue to play around with this solution or you simply destroy the stack.
Notes:
If you’re wondering why the connectionIds are stored in DynamoDB, that’s for example if an admin would love to send a broadcast message to all opened connections.
In the current implementation, this Table is not needed, but could be used for different other purposes, as explained above.
Thank you for reading! I hope you found it interesting.