aws-sdk-js-v3: API Gateway Management API post to connection throws connection refused

Describe the bug I’m unable to send websocket message to API Gateway from Lambda using new v3 SDK.

SDK version number@aws-sdk/client-apigatewaymanagementapi”: “1.0.0-alpha.22”

Is the issue in the browser/Node.js? Node.js

Details of the browser/Node.js version Lambda with Node v12.x

To Reproduce (observed behavior) This code (TypeScript):

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

const apiGatewayManagementApi = new ApiGatewayManagementApiClient({
  apiVersion: "2018-11-29",
  endpoint: event.requestContext.domainName + "/" + event.requestContext.stage,
});

await apiGatewayManagementApi.send(
  new PostToConnectionCommand({
    // @ts-ignore
    Data: "hello from lambda!",
    ConnectionId: event.requestContext.connectionId!,
  })
);

throws an error:

{
    "errorType": "Error",
    "errorMessage": "connect ECONNREFUSED 127.0.0.1:443",
    "code": "ECONNREFUSED",
    "errno": "ECONNREFUSED",
    "syscall": "connect",
    "address": "127.0.0.1",
    "port": 443,
    "$metadata": {
        "retries": 0,
        "totalRetryDelay": 0
    },
    "stack": [
        "Error: connect ECONNREFUSED 127.0.0.1:443",
        "    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1134:16)"
    ]
}

Moreover, I believe the type for the Data parameter in the command is wrong. It is Uint8Array, but when I provided data of this type, I get an error that “chunk expected string, got object”. So I put string there and ignored type mismatch.

Expected behavior With this code for the stable v2 aws-sdk (v2.639.0):

import ApiGatewayManagementApi from "aws-sdk/clients/apigatewaymanagementapi";

const apiGatewayManagementApi = new ApiGatewayManagementApi({
  apiVersion: "2018-11-29",
  endpoint: event.requestContext.domainName + "/" + event.requestContext.stage,
});

await apiGatewayManagementApi
  .postToConnection({
    ConnectionId: event.requestContext.connectionId!,
    Data: "hello from lambda!",
  })
  .promise();

everything works.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 15 (5 by maintainers)

Most upvoted comments

@m-radzikowski we’ll make a change to throw error when protocol is not passed by switching to WHATWG URL API.

$ node           
Welcome to Node.js v14.15.1.
Type ".help" for more information.
> process.version
'v14.15.1'
> const { parse } = require("url");
undefined
> parse("REMOVED.execute-api.eu-central-1.amazonaws.com/v1");
Url {
  protocol: null,
  slashes: null,
  auth: null,
  host: null,
  port: null,
  hostname: null,
  hash: null,
  search: null,
  query: null,
  pathname: 'REMOVED.execute-api.eu-central-1.amazonaws.com/v1',
  path: 'REMOVED.execute-api.eu-central-1.amazonaws.com/v1',
  href: 'REMOVED.execute-api.eu-central-1.amazonaws.com/v1'
}
> new URL("REMOVED.execute-api.eu-central-1.amazonaws.com/v1");
Uncaught:
TypeError [ERR_INVALID_URL]: Invalid URL: REMOVED.execute-api.eu-central-1.amazonaws.com/v1
    at onParseError (internal/url.js:258:9)
    at new URL (internal/url.js:334:5)
    at REPL9:1:1
    at Script.runInThisContext (vm.js:132:18)
    at REPLServer.defaultEval (repl.js:484:29)
    at bound (domain.js:430:14)
    at REPLServer.runBound [as eval] (domain.js:443:12)
    at REPLServer.onLine (repl.js:817:10)
    at REPLServer.emit (events.js:327:22)
    at REPLServer.EventEmitter.emit (domain.js:486:12) {
  input: 'REMOVED.execute-api.eu-central-1.amazonaws.com/v1',
  code: 'ERR_INVALID_URL'
}

url.parse has been deprecated and it recommends using the WHATWG URL API https://nodejs.org/api/url.html#url_url_parse_urlstring_parsequerystring_slashesdenotehost

WHATWG URL has been available on Global Object since v10.0.0, the minimum Node.js version we support. https://nodejs.org/api/url.html#url_the_whatwg_url_api

I also encountered this issue, was able to circumvent by passing in an object that implements the Endpoint interface.

        this.s3 = new S3({
            region: "[region]",
            endpoint: {
                protocol: "https",
                hostname: "[YOUR HOSTNAME]",
                path: ""
            },
        });

Full interface if you need more properties:

export interface Endpoint {
  protocol: string;
  hostname: string;
  port?: number;
  path: string;
  query?: QueryParameterBag;
}

Note: I am on version 1.0.0-rc.7

FWIW, I hit the same problem on 1.0.0-gamma.11.

@m-radzikowski The failed request was sent to endpoint 127.0.0.1:443. It means the the endpoint you supplied was not parsed correctly. Can you share an example of the endpoint you supplied? event.requestContext.domainName + '/' + event.requestContext.stage