jarv.org

Moving to HTTP from REST for the AWS API Gateway

HTTP API Gateway

When HTTP API Gateway was announced in 2019 the Amazon said:

Our goal is to make it as easy as possible for developers to build and manage APIs with API Gateway. We encourage you to try the new HTTP APIs and let us know what you think.

Today I decided to switch from using the REST API for cmdchallenge.com to the HTTP API and I must say it is a lot easier to build and setup for simple HTTP APIS. In Terraform, it now only requires two resources:

resource "aws_apigatewayv2_api" "default" {
  ...
}

resource "aws_lambda_permission" "default" {
  ...
}

Compare this to the previous configuration using REST API:


resource "aws_api_gateway_rest_api" "default" {
  ...
}

resource "aws_api_gateway_method" "default" {
  ...
}

resource "aws_api_gateway_integration" "default" {
  ...
}

resource "aws_lambda_permission" "default" {
  ...
}

resource "aws_api_gateway_deployment" "default" {
  ...
}

For a full working example, see the API Gateway Terraform configuration for cmdchallenge.com. In addition to making the configuration simpler, it’s supposed to be optimized for performance and this doesn’t disappoint either. Testing against an API endpoint that invokes a Lambda function and makes some DynamoDB calls there is a nice saving of around 100ms for the 50th percentile and 200ms for the 90th.

REST API Gateway:

 $ bombardier --latencies --rate 50 -d 30s 'https://g4jrkpyb3d.execute-api.us-east-1.amazonaws.com/r/?cmd=echo+hello+world&challenge_slug=hello_world'
Bombarding https://g4jrkpyb3d.execute-api.us-east-1.amazonaws.com:443/r/?cmd=echo+hello+world&challenge_slug=hello_world for 30s using 125 connection(s)
[============================================================================================================================================================================] 30s
Done!
Statistics        Avg      Stdev        Max
  Reqs/sec        48.45      33.81     211.47
  Latency         1.13s   845.04ms      6.77s
  Latency Distribution
     50%      0.88s
     75%      0.99s
     90%      2.71s
     95%      2.92s
     99%      4.78s
  HTTP codes:
    1xx - 0, 2xx - 1501, 3xx - 0, 4xx - 0, 5xx - 0
    others - 0
  Throughput:    86.94KB/s

HTTP API Gateway:

$ bombardier --latencies --rate 50 -d 30s 'https://ddzt9hixi4.execute-api.us-east-1.amazonaws.com/?cmd=echo+hello+world&challenge_slug=hello_world'
Bombarding https://ddzt9hixi4.execute-api.us-east-1.amazonaws.com:443/?cmd=echo+hello+world&challenge_slug=hello_world for 30s using 125 connection(s)
[============================================================================================================================================================================] 30s
Done!
Statistics        Avg      Stdev        Max
  Reqs/sec        48.44      30.62     235.42
  Latency         0.93s   679.98ms      6.70s
  Latency Distribution
     50%   703.40ms
     75%   731.99ms
     90%      1.66s
     95%      2.70s
     99%      3.98s
  HTTP codes:
    1xx - 0, 2xx - 1501, 3xx - 0, 4xx - 0, 5xx - 0
    others - 0
  Throughput:    33.19KB/s

Caching Responses with the HTTP API Gateway

Command Challenge has multiple layers of caching for anonymous usage. If there wasn’t any caching, every single submission would execute in a Docker container, which would not only be atrocious from a performance standpoint but also expensive as it would require multiple/large VMs executing commands in containers.

Every command that is submitted is hashed, and written to a DynamoDB table. If a subsequent command is identical for the same challenge, we return a cached response. Putting CloudFront in front of API Gateway is a nice way to get additional caching for free, which works for the HTTP Gateway which doesn’t have a caching feature. To cache HTTP API Gateway responses, create a CloudFront distribution with the API endpoint as the Origin Domain Name.