# AWS API Gateway Websocket With Lambda

Real-time communication is a core requirement for modern applications like chat apps, live dashboards, multiplayer games, and notifications. AWS makes this easier with **API Gateway WebSockets** and **AWS Lambda**, allowing you to build scalable, serverless, real-time APIs without managing servers.

In this blog, we’ll walk through **how to set up an AWS WebSocket API using API Gateway and Lambda**, including connection handling, messaging, and deployment.

## Create a API Gateway Websocket based endpoint

Open the API Gateway on aws console and create a websocket api.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1767028889840/cf56dfcb-552c-4d1e-a6ad-6cbaba4c5ce2.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1767028906082/ae7ac6cb-c78c-4a11-adb5-bab5d035a501.png align="center")

Then give your api a name and add the route selection expression (i’m going to leave it with the default `request.body.action`).

The way route selection works is when someone sends a message to your api gateway websocket endpoint, they pass an action along with the message. This action determines what lambda function we invoke in the backend (It’ll make more sense further into the blog).

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1767030286335/57f6247c-b721-422c-96ac-3416f1e7248a.png align="center")

Next, setup the predefined and custom routes. In addition to `$connect` and `$disconnect` routes I’m going to define a `sendMessage` route.

In an API Gateway **WebSocket API**, routes define what code runs when something happens on a WebSocket connection. Unlike REST APIs (which respond to HTTP methods like GET or POST), WebSocket APIs respond to **connection events and messages**.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1767030828041/350c9868-6b02-4192-b56b-5feffbca5066.png align="center")

Now we’re going to add integrations for all of our routes. As the blog title suggests the integration type will be **Lambda**. We’ll see what goes into the lambda functions in detail further into the blog.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1767048183818/9d0da741-86e7-41df-b03b-8ba46a28c14d.png align="center")

Finally name your stage, create and deploy the websocket.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1767048314990/9efa88fc-5d65-4cb5-b7de-77b235184572.png align="center")

## Let’s Explore the Websocket

Go to the API Gateway home page and open the Demo api we just created. Here you’ll see all the routes we configured. Make sure to deploy the api if you make any changes to the routes in the future.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1767048826922/a16c9517-a786-4b3b-913b-b285305d601e.png align="center")

To start messing with the websocket we’ll need the websocket endpoint. Go to stages &gt; production (or whatever the name of your stage is).

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1767049062628/044ef68b-e440-4410-9ab7-443fb646da10.png align="center")

Now, to test the websocket URL you can use any of the online websocket testing tools or postman. I’m using [https://piehost.com/websocket-tester](https://piehost.com/websocket-tester). Paste the websocket URL and connect.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1767049357365/fa95d12b-a96b-4d7e-94a2-cfb3c90a7ba9.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1767049374058/ec37e8e2-b88f-4e1f-8584-9b2d7f690e8b.png align="center")

## Now let’s talk Lambdas

Now that we are connected to the websocket let’s define our lambdas and how we want them to respond to the sendMessage route and broadcast messages to all active connections. Just go ahead and create 4 basic lambdas. I’m using Node.js, you can use the Runtime of your choice.

We have 4 functions here, we’ve already mapped three(`connect`, `disconnect` and `sendMessage`) of them to the routes while creating the websocket. broadcast is how we’ll communicate with all active connections.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1767049895283/06aeea8f-45b0-49fb-8af6-c904fb9a0b79.png align="center")

Always remember to return as `statusCode` 200 from your lambda function. This indicates to the API Gateway that the function executed successfully and the data should be passed back to the connected client as a message.

```javascript
export const handler = async (event) => {
  console.log('event', event);
  // TODO implement
  const response = {
    statusCode: 200,
    body: JSON.stringify('Hello from Lambda!'),
  };
  return response;
};
```

As we are already connected, So let’s go to the monitor tab and check the cloud watch logs for the connect function.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1767050477556/b1fc273d-5681-4f3c-aa80-f0fb93e80331.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1767050635840/39844980-d098-4c5d-9b4b-faa2b07ecba3.png align="center")

And open the latest log stream

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1767050652085/aae62a4a-378b-471b-9013-b2b603cf760d.png align="center")

What we are looking for here is the event and the requestContext. We are looking for the `connectionId` in particular:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1767050827263/83cc2906-d03a-4147-b1fe-867177fde070.png align="center")

The `connectionId` will be unique for each connection. When you are dealing with applications where there are multiple users connnected at a point, you might want to save these `connectionId`’s to a database to keep a track of all the connections that are active.

## SendMessage Lambda

The following is the code for **SendMessage** Lambda. We’ll use the `ApiGatewayManagementApiClient` to respond to messages. Get the endpoint URL from API Gateway, and `PostToConnectionCommand` is used to post message back to the connected client. Remember to return a statusCode of 200 at the end of every lambda.

```javascript
import {
  ApiGatewayManagementApiClient,
  PostToConnectionCommand
} from "@aws-sdk/client-apigatewaymanagementapi";

const client = new ApiGatewayManagementApiClient({
  endpoint: "https://xxxxxxxxxx.com/production"
});

export const handler = async (event) => {
  console.log(event);

  // Extract connectionId from incoming event
  const connectionId = event.requestContext.connectionId;

  // Do something interesting...
  const responseMessage = "responding...";

  // Post message back to the connected client
  const command = new PostToConnectionCommand({
    ConnectionId: connectionId,
    Data: Buffer.from(JSON.stringify(responseMessage))
  });

  await client.send(command);

  return {
    statusCode: 200
  };
};
```

In addition to this, any lambda function that uses `ApiGatewayManagementApiClient` to post back to an endpoint needs to have the `AmazonAPIGatewayInvokeFullAccess` permission policy, Add the `AmazonAPIGatewayInvokeFullAccess` permission policy to the `SendMessage-role` under lambda permissions. Don’t forget to redeploy your lambda after adding any new policies to the function’s role.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1767239662533/1d7c6d90-bec5-408c-8b6a-f6b3404835b1.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1767239696151/737ef9fb-3a3c-4bc7-a9b2-97984dcbf076.png align="center")

Now to send the message, remember the **Route selection expression** we used in the start while creating the API gateway endpoint? That is what we’ll use. The request goes something like this:

```javascript
{"action": "sendMessage", "message": "hello"}
```

You’ll see the “responding…“, which means your message has been received.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1767239741246/f1140d5d-fa34-4856-94fb-09ed21ff13a0.png align="center")

## Broadcast Lambda

This is what we’ll use to push messages to all the available clients that are currently connected. If you look at the code this does something very similar to the **SendMessage** lambda. We’ll pass the `connectionId` of the user in the event along with the `message`.

```javascript
import {
  ApiGatewayManagementApiClient,
  PostToConnectionCommand
} from "@aws-sdk/client-apigatewaymanagementapi";

const client = new ApiGatewayManagementApiClient({
  endpoint: "https://xxxxxx.com/production"
});

export const handler = async (event) => {
  // Extract connectionId and message from input
  const { connectionId, message } = event;

  // Send message to the given connectionId
  const command = new PostToConnectionCommand({
    ConnectionId: connectionId,
    Data: Buffer.from(JSON.stringify(message))
  });

  const response = await client.send(command);
  console.log(response);
};
```

This is how the request looks like, (You can get the `connectionId` from request in the Cloudwatch logs, when the user `connected` or during `sendMessage`):

```javascript
{
  "connectionId": "WfPxee4tvHcCJIw=",
  "message": "Is anyone online?"
}
```

Once you deploy the function, Create a new test event. Add the above request to **Event JSON** and **Invoke**. Don’t forget to apply the same permission policy to Broadcast function that we applied to SendMessage (`AmazonAPIGatewayInvokeFullAccess`).

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1767505151896/925b004b-3b11-482f-aec9-9960fc4a425e.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1767504240158/62e10a68-f60f-4bf9-8151-055381272106.png align="center")

## The End

AWS API Gateway WebSockets combined with Lambda offer a powerful, fully serverless way to build real-time applications. Once you understand how `$connect`, `$disconnect`, `$default`, and custom routes work together, the overall model becomes surprisingly simple and flexible.

In this guide, we covered how to set up a WebSocket API, route messages correctly, and send responses back to connected clients using the API Gateway Management API. From here, you can extend this foundation with authentication, DynamoDB-backed connection management, broadcasting, or more advanced message routing.

If you’re building chat systems, live dashboards, multiplayer features, or real-time notifications, this architecture gives you a scalable solution without the operational overhead of managing servers.

Happy building!
