Some data to help you choose between the AWS API Gateway service or Lambda Function URLs for your Serverless APIs.

A Quick Introduction to API Gateway and Lambda Function URLs

After building a couple of serverless online services such as SnapSecret, I've considered the use of Lambda Function URLs over API Gateways. After some experimentation and research, I've decided to share some of my findings in the form of a blog post. When building serverless APIs backed with Lambda Functions, there are currently 2 options AWS provides that can achieve this.

  1. Deploy and configure an API Gateway
  2. Configure your AWS Lambda with a URL

The Amazon API Gateway is a feature-rich service that allows you to create a RESTful API that can be invoked via HTTP, including features such as authentication, throttling, caching, logging, and monitoring. By making use of the configuration options provided, you reduce the amount of development effort required to build a robust and functional API.

In comparison, Lambda Function URLs allow you to set up a basic HTTP endpoint that can be used to invoke a single Lambda function. This is useful if you quickly need a way to invoke a Lambda function via HTTP, but don't need the full functionality of the API Gateway.

Feature Comparison

This table represents a comparison of the features natively (no additional logic needs to be implemented within your Lambda code) provided by these services.

Steven CGP 1.png

  • When configuring Authentication for Lambda Function URLs, you can only configure IAM users and roles authentication.

** Throttling can be performed by using the AWS Lambda provisioned concurrency feature, but you are not able to throttle per IP address or API key.

As you can see, the feature set provided by the API Gateway is much more extensive than the Lambda Function URL. Due to this, the use cases for both services are different and will vary based on your requirements. If you need support for any of the features outlined above, it would be better to rely on the API Gateway service rather than baking your own as the development cost will significantly outweigh the cost of using the API Gateway.

Cost Comparison

For the cost comparison, I will assume the following details in the ap-southeast-2 region:

1 million requests per month Response payload of 1KB 512MB of Lambda Function Memory An execution time of 150ms

Lambda Function Pricing

Due to the lifetime free tier available for Lambda functions, executing the lambda function will not cost anything to operate in this case. Even if we exclude or go over the AWS Free Tier usage, this will cost a total of USD 1.45 per month:

1,000,000 requests x 150 ms x 0.001 ms to sec conversion factor = 150,000.00 total compute (seconds)
0.50 GB x 150,000.00 seconds = 75,000.00 total compute (GB-s)
Tiered price for: 75000.00 GB-s
75000 GB-s x 0.0000166667 USD = 1.25 USD
Total tier cost = 1.2500 USD (monthly compute charges)
1,000,000 requests x 0.0000002 USD = 0.20 USD (monthly request charges)
0.50 GB - 0.5 GB (no additional charge) = 0.00 GB billable ephemeral storage per function
1.25 USD + 0.20 USD = 1.45 USD

API Gateway Pricing

API Gateways come in 2 variations, the HTTP API and the REST API. A comparison of the two can be found in the AWS Documentation for Choosing between REST APIs and HTTP APIs. An excerpt directly from the documentation reads as follows:

REST APIs and HTTP APIs are both RESTful API products. REST APIs support more features than HTTP APIs, while HTTP APIs are designed with minimal features so that they can be offered at a lower price. Choose REST APIs if you need features such as API keys, per-client throttling, request validation, AWS WAF integration, or private API endpoints. Choose HTTP APIs if you don't need the features included with REST APIs.

I will provide the pricing for both HTTP and REST APIs, but will only be comparing the REST API as it is the more feature-rich option.

# HTTP API
1 KB per request / 512 KB request increment = 0.001953125 request(s)
RoundUp (0.001953125) = 1 billable request(s)
1 requests per month x 1,000,000 unit multiplier x 1 billable request(s) = 1,000,000 total billable request(s)
Tiered price for: 1000000 requests
1000000 requests x 0.0000012900 USD = 1.29 USD
Total tier cost = 1.2900 USD (HTTP API requests)
HTTP API request cost (monthly): 1.29 USD

# REST API
1 requests x 1,000,000 unit multiplier = 1,000,000 total REST API requests
Tiered price for: 1000000 requests
1000000 requests x 0.0000035000 USD = 3.50 USD
Total tier cost = 3.5000 USD (REST API requests)
Tiered price total for REST API requests: 3.50 USD
0 USD per hour x 730 hours in a month = 0.00 USD for cache memory
Dedicated cache memory total price: 0.00 USD
REST API cost (monthly): 3.50 USD

Total Pricing

The cost difference for these services is not significant, but it is still worth noting that the Lambda Function URL is cheaper purely on a cost-per-request basis.

API Gateway

$1.45 USD for Lambda Function + $3.50 USD for REST API = $4.95 USD per month

Lambda Function URL

$1.45 USD for Lambda Function = $1.45 USD per month

When to use API Gateways

API Gateways should be used when you need to build a robust and feature-rich API that can be invoked via HTTP. This is a good option if you need to support any of the features outlined above, support multiple Lambda functions or even proxying requests to other services. Enhancing the authorisation and authentication capabilities of your API Gateway can even be done via Lambda Authorisors to support custom authentication methods such as JWTs.

API Gateways are purpose-built with building APIs in mind, so anything more than a single purpose, simple API should be built using the API Gateway service.

When to use Lambda Functions URLs

Lambda Function URLs should be used when you need to quickly set up an HTTP endpoint to invoke a single Lambda function. This is a good option if you need to quickly set up an HTTP endpoint to invoke a Lambda function, but don't need the full functionality of the API Gateway. This can range from anything like a webhook or a single lambda function that requires HTTP invocation capabilities. Anything beyond a simple HTTP -> lambda invocation should be built using the API Gateway service, as the moment you require any of the features outlined in the features comparison section, you will need to build your logic to support them. This adds complexity and development costs that will outweigh the cost savings you will realise when using the Lambda Function URL.

Performance Comparison

To do a performance comparison, I have opted to use a tool called apache benchmark to send traffic at both endpoints and measure the response times. In the test, I used a concurrency of 10 and a total of 2500 requests from a single machine hosted outside of AWS. This low concurrency value is to avoid any HTTP rate-limiting that may occur when sending a large amount of traffic from the single machine as well as reducing concurrent lambda executions resulting in lambda throttling.

Lambda Function URLs For the Lambda Function URLs, we were able to send 2000 requests in about 4 seconds with an average response time of 2.024ms/request.

sktan@testvm:~$ ab -c 10 -n 2000 https://basdf1234.lambda-url.ap-southeast-2.on.aws/
This is ApacheBench, Version 2.3 <$Revision: 1807734 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking basdf1234.lambda-url.ap-southeast-2.on.aws (be patient)
Completed 200 requests
Completed 400 requests
Completed 600 requests
Completed 800 requests
Completed 1000 requests
Completed 1200 requests
Completed 1400 requests
Completed 1600 requests
Completed 1800 requests
Completed 2000 requests
Finished 2000 requests

Server Software:        
Server Hostname:        basdf1234.lambda-url.ap-southeast-2.on.aws
Server Port:            443
SSL/TLS Protocol:       TLSv1.2,ECDHE-RSA-AES128-GCM-SHA256,2048,128
TLS Server Name:        basdf1234.lambda-url.ap-southeast-2.on.aws

Document Path:          /
Document Length:        20 bytes

Concurrency Level:      10
Time taken for tests:   4.048 seconds
Complete requests:      2000
Failed requests:        13
   (Connect: 0, Receive: 0, Length: 13, Exceptions: 0)
Non-2xx responses:      13
Total transferred:      544767 bytes
HTML transferred:       40897 bytes
Requests per second:    494.06 [#/sec] (mean)
Time per request:       20.240 [ms] (mean)
Time per request:       2.024 [ms] (mean, across all concurrent requests)
Transfer rate:          131.42 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        6    8   1.2      8      14
Processing:     5   12   3.9     11      54
Waiting:        5   12   3.8     11      54
Total:         12   20   4.0     19      64

Percentage of the requests served within a certain time (ms)
  50%     19
  66%     20
  75%     21
  80%     22
  90%     25
  95%     28
  98%     31
  99%     34
 100%     64 (longest request)

API Gateway

For the API Gateway, we had very similar results with 2000 requests taking about 4.6 seconds with an average response time of 2.324ms/request.

sktan@testvm:~$ ab -c 10 -n 2000 https://basdf1234.execute-api.ap-southeast-2.amazonaws.com/testlambda-apigw
This is ApacheBench, Version 2.3 <$Revision: 1807734 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking basdf1234.execute-api.ap-southeast-2.amazonaws.com (be patient)
Completed 200 requests
Completed 400 requests
Completed 600 requests
Completed 800 requests
Completed 1000 requests
Completed 1200 requests
Completed 1400 requests
Completed 1600 requests
Completed 1800 requests
Completed 2000 requests
Finished 2000 requests

Server Software:        
Server Hostname:        basdf1234.execute-api.ap-southeast-2.amazonaws.com
Server Port:            443
SSL/TLS Protocol:       TLSv1.2,ECDHE-RSA-AES128-GCM-SHA256,2048,128
TLS Server Name:        basdf1234.execute-api.ap-southeast-2.amazonaws.com

Document Path:          /testlambda-apigw
Document Length:        20 bytes

Concurrency Level:      10
Time taken for tests:   4.648 seconds
Complete requests:      2000
Failed requests:        0
Total transferred:      382000 bytes
HTML transferred:       40000 bytes
Requests per second:    430.29 [#/sec] (mean)
Time per request:       23.240 [ms] (mean)
Time per request:       2.324 [ms] (mean, across all concurrent requests)
Transfer rate:          80.26 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        6    7   0.8      7      12
Processing:     9   16   4.1     15      65
Waiting:        9   16   4.1     15      65
Total:         16   23   4.2     22      72

Percentage of the requests served within a certain time (ms)
  50%     22
  66%     23
  75%     24
  80%     25
  90%     29
  95%     31
  98%     34
  99%     36
 100%     72 (longest request)

Comparing the Two Results

The results are very similar, with the API Gateway being slightly slower than the Lambda Function URL though I assume this is likely to do with the additional processing that the API Gateway does when handling the request. If we have a look at the P99 values, we can see that there was only a 2ms difference for 10 concurrent requests. This tiny difference is not enough to sway your decision into choosing a Lambda Function URL over running an API Gateway to increase API performance and you would likely be able to find better results by optimising your code or running on a more recent Lambda Runtime version.

Conclusion

After the analysis, what I've found is that unless you don't need any of the features provided by the API Gateway both in the short and long term, you should be using the Amazon API Gateway service. The biggest benefit of using a Lambda Function URL is if you need to quickly set up an HTTP endpoint to invoke a Lambda function but without any of the additional capabilities offered by the API Gateway. An example of when this might be the case is if you were to build a simple standalone webhook that processes some information and returns some data to the caller. This could be a webhook that is used to process a payment or used to process a form submission (e.g a contact form). In this case, you would not need any of the additional features offered by the API Gateway, so it would be more cost-effective to use the Lambda Function URL.