How to Rename API Gateway Path Parameters on AWS
Tags: javascript, aws, tutorial, serverless
Published: 2023-07-06 12:54:49

Renaming a path parameter in AWS API Gateway can be a complex task, whether you're working with a REST API using aws-apigateway (v1) module or an HTTP API with aws-apigatewayv2 (v2). In this article, we'll explore the process of renaming path parameters for both modules and discuss two solutions to achieve the desired result without causing disruptions for your users.

**Code for REST API (v1)**

```typescript
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as apigateway from 'aws-cdk-lib/aws-apigateway';

const getArticle = new lambda.Function(this, 'GetArticle', {
  runtime: lambda.Runtime.NODEJS_14_X,
  handler: 'index.handler',
  code: lambda.Code.fromAsset('path/to/getArticle/code'),
});

const restApi = new apigateway.RestApi(this, 'MyRestApi');

restApi.root
  .resourceForPath('/get-article/{id}')
  .addMethod('GET', new apigateway.LambdaIntegration(getArticle));
```

**Code for HTTP API (v2)**

```typescript
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as apigatewayv2 from 'aws-cdk-lib/aws-apigatewayv2';
import * as integrations from 'aws-cdk-lib/aws-apigatewayv2-integrations';

const getArticle = new lambda.Function(this, 'GetArticle', {
  runtime: lambda.Runtime.NODEJS_14_X,
  handler: 'index.handler',
  code: lambda.Code.fromAsset('path/to/getArticle/code'),
});

const httpApi = new apigatewayv2.HttpApi(this, 'MyHttpApi');

httpApi.addRoutes({
  path: '/get-article/{id}',
  methods: ['GET'],
  integration: new integrations.LambdaProxyIntegration({
    handler: getArticle,
  }),
});
```

Let's consider a scenario where you need to retrieve an article not only by its `id`, but also based on its association with newsletters. In this case, you want to modify the endpoint path from `/get-article/{id}` to `/get-article/{newsletterId}/{articleId}`. Although this change is purely semantic, you can assign the value of `id` to `newsletterId` and introduce a new parameter called `articleId`.

To simplify matters, let's focus on the objective of renaming the `id` parameter to `articleId`.

However, implementing this update is not as straightforward as it may initially appear. When you attempt to deploy the changes using `npx cdk deploy`, you will encounter the following error messages:

- For the REST API (v1)

```bash
Resource handler returned message: "A sibling ({id}) of this resource already has a variable path part -- only one is allowed (Service: ApiGateway, Status Code: 400, ...
```

- For the HTTP API (v2)

```bash
Resource handler returned message: "The provided route key "GET /get-article/{articleId}" has a conflicting variable on the same hierarchical level as "GET /get-article/{id}" (Service:
AmazonApiGatewayV2; Status Code: 409; Error Code: ConflictException;
```

There are two main solutions for renaming API path parameters.

## Solution 1: Comment, Deploy, Update, and Redeploy

Pros: Straightforward and easy to implement.

Cons: Requires a maintenance window and downtime for your users if the route is used in production.

- Comment out the API resource containing the old path parameter.
```typescript
// restApi.root
//   .resourceForPath('/get-article/{id}')
//   .addMethod('GET', new apigateway.LambdaIntegration(getArticle));
```
- Deploy the changes using `npx cdk deploy`.
- Uncomment the previously commented code and modify the path parameter name from `id` to `articleId`.
```typescript
restApi.root
  .resourceForPath('/get-article/{articleId}')
  .addMethod('GET', new apigateway.LambdaIntegration(getArticle));
```
- Deploy the changes again with `npx cdk deploy`.

By following this approach, you can effectively update the path parameter without directly renaming it. However, be mindful of the downtime it may cause during the deployment window.

_Note: An alternative approach would be to manually delete the corresponding resource from the AWS console. While this method might be successful in certain scenarios, it is not recommended due to potential complications it may introduce to the CDK stack._

## Solution 2: Creating and Migrating to a New Resource

Pros: No downtime for your users.

Cons: Requires maintenance of two resources temporarily, and client code updates are necessary to migrate from the old resource to the new one.

To rename a path parameter using this method, follow these steps:

- Create a new resource with a new path, but maintaining the same integration and methods as the old resource. (For example, `/get-article/v2/{articleId}`).
```typescript
restApi.root
  .resourceForPath('/get-article/{id}')
  .addMethod('GET', new apigateway.LambdaIntegration(getArticle));

// Add a new resource with the new path parameter name
restApi.root
  .resourceForPath('/get-article/v2/{articleId}')
  .addMethod('GET', new apigateway.LambdaIntegration(getArticle));
```
- Migrate from the old resource to the new one by updating the client code to use the new path parameter name. Once the migration is complete, you can safely remove the old resource.
- Optionally, rename the new resource to match the old resource's name, but with the new path parameter name (`/get-article/{articleId}`). Ensure that the client code is updated accordingly.
```typescript
// Remove these lines
// restApi.root
//   .resourceForPath('/get-article/{id}')
//   .addMethod('GET', new apigateway.LambdaIntegration(getArticle));

restApi.root
  // Remove the `/v2` suffix
  .resourceForPath('/get-article/{articleId}')
  .addMethod('GET', new apigateway.LambdaIntegration(getArticle));
```
This solution guarantees uninterrupted service for your users. However, it involves temporarily managing two resources and coordinating the migration process with client-side updates.

## Conclusion

By following these steps, you can successfully rename path parameters in API Gateway on AWS.
The second solution is highly recommended due to its robustness and the advantage of avoiding downtime for your users. However, if you are in a hurry or your production environment does not have active users, the first solution is also a viable option to consider.