aws-api-gatewayaws-amplifyaws-appsyncaws-iotamplifyjs

AmplifyJS error when Appsync subscribe is exposed via API Gateway


Appsync is already replacing API Gateway to some extend, then why do you need to expose it via API Gateway. I know most people would be asking this question. Here is why?

  1. Support for Usage Plan
  2. Possibility of monetization.

As far as I understood, Appsync is GrapQL + Apollo server implementation. The API exposed supports POST request. And even the subscription request is also a post request with Websocket MQTT (AWS IoT) URL as the response. (Eg provided below)

{
  "extensions": {
    "subscription": {
      "mqttConnections": [
        {
          "url": "wss://something-ats.iot.ap-northeast-1.amazonaws.com/mqtt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...",
          "topics": [
            ".../.../subscribeToVehicleLocation/..."
          ],
          "client": "..."
        }
      ],
      "newSubscriptions": {
        "subscribeToVehicleLocation": {
          "topic": ".../../subscribeToVehicleLocation/..",
          "expireTime": null
        }
      }
    }
  },
  "data": {
    "subscribeToVehicleLocation": null
  }
}

If that is the case, can we expose Appsyn endpoint via API-Gateway (POST Method)?

For simplicity, I tried with HTTP API in API-Gateway.

PS:

I was previously able to subscribe to the data using the original Appsync URL (using AmplifyJS in Angular 7). With API-Gateway URL, I am getting this WS Handshake exception (with Amplify).

WebSocket connection to 'wss://....execute-api.ap-northeast-1.amazonaws.com/graphql?header=...&payload=e30=' failed: Error during WebSocket handshake: Unexpected response code: 400

in AWSAppSyncRealTimeProvider.js:603 

Update 24-04-2020

I was able to invoke Appsync via AWS Service invoke in API-Gateway with the below settings. (Used REST Protocol provided by API Gateway)

But still, I am having the Web Socket error in Amplify

API-Gateway Configuration

AWS API Gateway invoking AWS Service Appsync

Note: AWS Subdomain, is the subdomain part of Appsync API Endpoint.

Trust relationship for IAM Role

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": [
          "appsync.amazonaws.com",
          "apigateway.amazonaws.com"
        ]
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

IAM Role Permission

API Gateway execution role


Solution

  • After getting expert opinions, I had finally dropped the plan of exposing Appsync via API-Gateway.

    Appsync & API-Gateway belongs to the same hierarchy in AWS Stack. It was not a good idea to expose Appsync via API-Gateway, since, Appsync endpoint would still be public (leading to a back door).

    Below are my solutions (considering Appsync alone) for

    1. Monetization Scope: Collect Appsync metrics/trace logs and calculate the API Usage based on Cognito UserId or Apikey.

    2. Usage Plan/Quota: Set up a Lambda Datasource (in Pipeline resolver) incrementing the hit count in Redis cache (with key as Apikey and value as hit count having a custom TTL say 1 day).

    If there are any better solutions, please feel free to share it.