Welcome to 'Back To Basics'.
I am Sid, and today we'll talk about an architecture pattern on how you can build
serverless asynchronous webapps using API Gateway and WebSockets.
Now before we dive into the AWS architecture,
let's spend a few minutes understanding
where and why would you use WebSockets and asynchronous communication.
Let's consider a scenario where you have a webapp hosted on a server
and a user is accessing the webapp through their laptop's web browser.
The web server has to communicate with downstream app server
in order to fulfill the request.
In a synchronous flow, user makes an HTTP request.
This request blocks the execution of code within the web page
until the response is received.
The freezing of web page isn't a good user experience,
especially when request response latency is high.
To solve this problem, developers typically use
AJAX APIs like XMLHttpRequest
and Fetch API to implement callbacks and promises.
Now while AJAX is great, there are use cases
where simply using these APIs isn't enough.
The first use case is where the request takes much longer to process and respond to
than what a TCP connection can stay active for.
And second, where the server needs to send messages to the user on demand.
Example here would be chat applications, multi-player games,
and financial trading platforms.
Now one way I have seen this use case being implemented is by using polling.
You can implement regular polling where you send a request to the server
and instead of immediately waiting for a response,
the client polls or reaches out to the server repeatedly
in a defined time interval, checking for a response or a new message.
Every poll is a new HTTP request and can result in an empty response,
so it's not very efficient.
Alternatively, you can implement long polling,
where the web server doesn't respond immediately,
but rather keeps the connection open for as long as it can without timing out,
and responds when it has something to report.
While better than regular polling,
long polling can still result in empty responses
and is very taxing on the server.
The better way is to use WebSockets.
WebSocket is a TCP-based protocol
which enables bi-directional full duplex communication,
where the client and the server can independently send messages to each other.
WebSocket protocol is much more light weight than long polling.
Now let's see how we can build serverless web architectures on AWS
using API Gateway and WebSockets.
In API Gateway your Websocket API accesses stateful frontend
for AWS services like Lambda and DynamoDB.
In your WebSocket API, incoming JSON messages
can be routed to the right back end based on the routes you define.
For our scenario, we will configure three routes.
First is a Connect route.
This is used when a client first connects to your WebSocket API.
You can define a Lambda proxy integration for this route,
which gets triggered when the user connects to the WebSocket API.
The Lambda function stores the WebSocket Connection ID
in a DynamoDB table.
We will see in a bit why that's required.
Next, you define a SendMessage route.
This is used when the user sends a message.
Another Lambda integration takes this message
and persist it into a DynamoDB table.
Next, leveraging DynamoDB streams, these messages can be
asynchronously processed by another Lambda function
that performs the business logic and generates the response.
Now you must be wondering why use a Lambda function
to write data to DynamoDB just to trigger another Lambda function to process it.
This is to decouple the back end processing from the incoming request.
If we were to push all the business logic to a single Lambda function,
and if this Lambda function takes too long or errors out,
we end up adding latency to our flow.
Additionally, if you had any downstream dependencies,
adding a queue or a stream acts as a buffer to store a pending request,
which can be consumed by the downstream processing layer
at a pace that works for them.
Using the connection ID which we persist it into DynamoDB earlier,
the Lambda function can create a callback URL,
which it uses to push a message to the client asynchronously.
Additionally, the Lambda function can push multiple messages to the user if required
using the same callback URL.
Note that a single WebSocket API connection can last for up to two hours,
so you don't have to worry about time-outs.
During this period, both parties can exchange any number of messages.
Finally, when the session is completed,
the user sends a disconnect which triggers the disconnect route.
Here, another Lambda integration can optionally clean up the entries
in the DynamoDB database.
In this session, we saw how WebSockets can enable
true asynchronous bi-directional communication
between a client and a server.
Further, we explored a serverless architecture
leveraging API Gateway, Lambda, and DynamoDB
to implement a WebSocket API on AWS.
Check out the links below for more details.
See you next time.