Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

API Versioning Approach With AWS API Gateway

DZone's Guide to

API Versioning Approach With AWS API Gateway

In this post, I have tried to describe the steps and artifacts require to implement Amazon API Gateway based REST API versioning strategy.

· Integration Zone ·
Free Resource

SnapLogic is the leading self-service enterprise-grade integration platform. Download the 2018 GartnerMagic Quadrant for Enterprise iPaaS or play around on the platform, risk free, for 30 days.

Abstract

In this post, I have tried to describe the steps and artifacts require to implement Amazon API Gateway based REST API versioning strategy.

Introduction

There is a requirement to versioning the REST API in one of our projects. These REST APIs should be generic enough to support multitenancy and multiple versions. As these APIs will be used by multiple customers, there is a possibility where two different customers can use two different versions of the API simultaneously.

As we are implementing our API using the Amazon API Gateway service, and we want to implement the recommended best approach. I was in a search to figure out the best versioning strategy using AWS API Gateway and Lambda. After spending a day in search, my understanding is that there are three gross strategies to version the REST API. 1) Create a completely new API with appending the version number at the end (e.g. www.mydomain.com/ordersV1, www.mydomain.com/ordersV2 something like this), 2) Putting the version indicator in the resource path (e.g. www.mydomain.com/api/v1/xxx, www.mydomain.com/api/v2/xxx) — It's a traditional approach. and 3) Create a completely new domain for the new version (v1.api.mysite.com, v2.api.mysite.com). We have to select our approach out of these three strategies.

Solution Approach

There is an option in the AWS API Gateway named Stage Variables. Inside theIntegration Request view, we can provide the stage variable name ( ${stageVariables.<stage variable name> } ) instead of the actual Lambda function name. During deployment, the stage variable can contain a different Lambda version (or alias), so that based on invoked resource (/api/v1/getOrders), staging environment (dev, prod etc.), and lambda name with version defined in stage variable, API Gateway can choose the corresponding function to invoke. We decided to exploit this feature to go with the traditional versioning approach i.e. resource path-based versioning. The next section explains the details of the manual implementation steps of this approach.

Solution Details

I create one simple NodeJs Lambda function with two versions and then created the AWS Gateway API resources to trigger those versions. All these steps described here are executed manually. Later, we will establish the AWS CodePipeline for Lambda version (or alias) deployment, but as per the current plan, we will not be automating the API deployment. It will be done manually as per the roadmap.

1. Create one nodejs lambda function getOrders .

2. Generate two versions of the function with some changes in the JSON response.

Image title

3. Create a test event to test the lambda. As I have a plan to create a LAMBDA_PROXY type integration in API Gateway, I select the API Gateway AWS Proxy template. The test event JSON request is given below.

{
  "body": "{\"test\":\"body\"}",
  "resource": "/dev/v1/orders",
  "requestContext": {
    "resourceId": "123456",
    "apiId": "1234567890",
    "resourcePath": "/dev/v1/orders",
    "httpMethod": "GET",
    "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef",
    "accountId": "123456789012",
    "identity": {
      "apiKey": null,
      "userArn": null,
      "cognitoAuthenticationType": null,
      "caller": null,
      "userAgent": "Custom User Agent String",
      "user": null,
      "cognitoIdentityPoolId": null,
      "cognitoIdentityId": null,
      "cognitoAuthenticationProvider": null,
      "sourceIp": "127.0.0.1",
      "accountId": null
    },
    "stage": "dev"
  },
  "queryStringParameters": {
    "start":"2015-10-01T00:00:00Z",
    "end":"2015-10-04T00:00:00Z"
  },
  "headers": {
    "Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)",
    "Accept-Language": "en-US,en;.8",
    "CloudFront-Is-Desktop-Viewer": "true",
    "CloudFront-Is-SmartTV-Viewer": "false",
    "CloudFront-Is-Mobile-Viewer": "false",
    "X-Forwarded-For": "127.0.0.1, 127.0.0.2",
    "CloudFront-Viewer-Country": "US",
    "Accept": "text/html,application/xhtml+xml,application/xml;.9,image/webp,*/*;.8",
    "Upgrade-Insecure-Requests": "1",
    "X-Forwarded-Port": "443",
    "Host": "1234567890.execute-api.us-east-2.amazonaws.com",
    "X-Forwarded-Proto": "https",
    "X-Amz-Cf-Id": "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==",
    "CloudFront-Is-Tablet-Viewer": "false",
    "Cache-Control": "",
    "User-Agent": "Custom User Agent String",
    "CloudFront-Forwarded-Proto": "https",
    "Accept-Encoding": "gzip, deflate, sdch"
  },
  "pathParameters": {
    "proxy": "path/to/resource"
  },
  "httpMethod": "GET",
  "stageVariables": {
    "v1fn": "getOrders:1",
    "v2fn":"getOrders:2"
  },
  "path": "/path/to/resource"
}

4. Following the minimum changes I did to test the lambda function:

  • Update resource and resourcePath with planned API Gateway resource path ( /dev/v<#>/orders).
  • httpMethod would be GET for this POC.
  • stage would be dev.
  • queryStringParameters are start and end timestamp.
  • I have a plan to create two versions of the API, each of which will point to the corresponding Lambda version in dev environment. For that, I have created two stageVariables ( v1fn and v2fn) with <function name>:<version number> ( getOrders:1 & getOrders:2)

That’s it. I am done with the test event creation. If I execute the event, I can see the getOrders function is returning the proper output.

5. Now, from the Amazon API Gateway menu, create an API with the following path for two API versions. For version 1, it is /v1/orders, and for version 2, it is /v2/orders .

6. The integration request type is LAMBDA_PROXY to pass queryStringParameters seamlessly.

Image title

7. To implement the LAMBDA_PROXY integration type, we need to do the following setup inside the Integration Request view.

Image title

Note: Here, instead of giving lambda function name, I specify ${stageVariables.<stage-variable-name>}to dynamically select a different function version (or alias).

8. The same setup is needed for /v2/orders resource.

9. Now we can test both the APIs from the API Test wizard.

Image title

Note: We have to enter the stage variable value here during the test (e.g. for v2fn it is getOrders:2), otherwise, the API will behave incorrectly.

10. Now deploy the API in dev stage. The API URI for different versions are as below:

  • https://xxxxxxxxxx.execute-api.xxxxxxxxx.amazonaws.com/dev/v1/orders
  • https://xxxxxxxxxx.execute-api.xxxxxxxxx.amazonaws.com/dev/v2/orders

Image title

Where the resources are /dev/v1/orders and /dev/v2/orders respectively.

Note: We have a plan to deploy lambda code using the AWS CodePipeline. As we have a limited number of APIs, we will manually create an API from the Amazon API Gateway console.

Conclusion

The following are common issues that we have addressed from this implementation.

Issues

How we address

No isolation. If we have a bug in v1 code that can be exploited, all our instances are vulnerable.

There are separate codes for each of the Lambda functions and as it is a functional programming approach, there is no common code between the versions.

Development limitations. We need to support the whole code base, making sure "v1" and "v2" live nicely together. Consider a situation when some dependency is used in both "v1" and "v2" but require specific different versions.

Both v1 and v2 Lambda function codes and their corresponding dependencies are mutually exclusive, so there would be no conflict.

Technology lock-in. It is either impossible or very hard to have "v1" in C# and "v2" in Python.

It may not be possible using Lambda implementation because there is 1:1 mapping between the Lambda function and the programming language.

Capacity planning and monitoring. It is hard to understand how much resources are consumed by "v1" calls vs. "v2."

We can monitor based on the complete and regular expression-based resource path.

Domain name-based and API name-based approaches can also be a possible solution, but as Amazon offers us so much flexibility, we are ardent to implement the versioning with its deepest component and can maintain the traditional flavor.

With SnapLogic’s integration platform you can save millions of dollars, increase integrator productivity by 5X, and reduce integration time to value by 90%. Sign up for our risk-free 30-day trial!

Topics:
aws api gateway ,rest api ,api versioning ,integration ,rest ,lambda ,api versioning solutions

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}