Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making an HTTPs request on AWS ApiGatewayV2 websocket connection to Respond, or Delete it

UPDATE

This issue is partially resolved, the problem now lies in authenticating the ApiGateway request. I am unsure of how to acquire the necessary tokens to send with the request so that it is valid, because this is a [serverless-framework] service so I can't use the AWS Console to copy paste the tokens into the request's json data. Moreover, I wouldn't know what json key they'd have to be under anyways. So I guess this question has changed considerably in scope.


I need to respond/delete an active websocket connection established through AWS ApiGatewayV2, in a Lambda. How do I use node js to send a POST request that ApiGateway can understand?

I saw on the websocket support announcement video that you could issue an HTTP POST request to respond to a websocket, and DELETE request to disconnect a websocket. Full table from the video transcribed here:

Connection URL
https://abcdef.execute-api.us-west-1.amazonaws.com/env/@connections/connectionId

Operation  Action
POST       Sends a message from the Server to connected WS Client
GET        Gets the latest connection status of the connected WS Client
DELETE     Disconnect the connected client from the WS connection

(this is not documented anywhere else, AFAIK)

Seeing as the AWS SDK does not provide a deleteConnection method on ApiGatewayManagementApi, I need to be able to issue requests directly to the ApiGateway anyways.

const connect = async (event, context) => {
  const connection_id = event.requestContext.connectionId;
  const host = event.requestContext.domainName;
  const path = '/' + event.requestContext.stage + '/@connections/';
  const json = JSON.stringify({data: "hello world!"});

  console.log("send to " + host + path + connection_id + ":\n" + json);

  await new Promise((resolve, reject) => {
    const options = {
      host: host,
      port: '443',
      path: path + connection_id,
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Content-Length': Buffer.byteLength(json)
      }
    };
    const req = https.request(
      options,
      (res) => {
        res.on('data', (data) => {
          console.error(data.toString());
        });
        res.on('end', () => {
          console.error("request finished");
          resolve();
        });
        res.on('error', (error) => {
          console.error(error, error.stack);
          reject();
        });
      }
    );
    req.write(json);
    req.end();
  });
  return success;
};

When I use wscat to test it out, this code results in the console.log showing up in CloudWatch:

send to ********.execute-api.us-east-2.amazonaws.com/dev/@connections/*************:
{
    "data": "hello world!"
}

...

{
    "message": "Missing Authentication Token"
}

...

request finished

And wscat says:

connected (press CTRL+C to quit)
>

But does not print hello world! or similar.

Edit

I was missing

res.on('data', (data) => {
  console.error(data.toString());
});

in the response handler, which was breaking things. This still doesnt work, though.

like image 228
Atlas Dostal Avatar asked Oct 16 '22 05:10

Atlas Dostal


1 Answers

You're likely missing two things here.

  1. You need to make an IAM signed request to the API Gateway per the documentation located here: Use @connections Commands in Your Backend Service
  2. You'll need to give this lambda permission to invoke the API Gateway per the documentation here: Use IAM Authorization

I hope this helps!

like image 195
Centinul Avatar answered Oct 19 '22 00:10

Centinul