AWS CDK Deployment fails: Invalid API identifier specified

Viewed 36

I am trying to add a new Route and Integration to my existing REST API in AWS API Gateway. I am using the below code snippet to make it happen:

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';

export interface IApiGatewayIntegrationProps extends cdk.StackProps {
  /**
   * Application Name. Will be used to name all the resources
   */
  appName: string;

  /**
   * Route name to add the API Gateway Integration onto.
   * For example: setting `admin` for admin-api, the invocation url will be `${apiGatewayInvocationUrl}/admin`
   */
  apiPath: string;

  /**
   * REST API ID for an existing API
   */
  restApiId: string;

  /**
   * ID for the root resource in the API
   */
  restApiRootResourceId: string;

  /**
   * VPC Link ID
   */
  VpcLink: string;

  /**
   * URL for the Network Load Balancer (NLB)
   */
  NLBDns: string;

  /**
   * Listener port on the NLB
   */
  NLBPort: number;
}

export class CustomApiGatewayIntegration extends Construct {
  constructor(scope: Construct, id: string, props: IApiGatewayIntegrationProps) {
    super(scope, id);

    const api = cdk.aws_apigateway.RestApi.fromRestApiAttributes(scope, 'api', {
      restApiId: props.restApiId,
      rootResourceId: props.restApiRootResourceId,
    });

    const proxyIntegration = new cdk.aws_apigatewayv2.CfnIntegration(this, 'gateway-integration', {
      apiId: api.restApiId,
      connectionId: props.VpcLink,
      connectionType: 'VPC_LINK',
      description: 'API Integration',
      integrationMethod: 'ANY',
      integrationType: 'HTTP_PROXY',
      integrationUri: `http://${props.NLBDns}:${props.NLBPort}/${props.apiPath}/{proxy}`,
    });

    new cdk.aws_apigatewayv2.CfnRoute(this, 'gateway-route', {
      apiId: api.restApiId,
      routeKey: 'ANY somepath/{proxy+}',
      target: `integrations/${proxyIntegration.ref}`,
    });
  }
}

After deploying the CDK Stack, I get the following error in the terminal:

failed: Error: The stack named $STACK_NAME failed to deploy: UPDATE_ROLLBACK_COMPLETE: Invalid API identifier specified $AWS_ACCOUNT_ID:$REST_API_ID

Error message in the terminal

This is how the error looks in the Cloudformation console:

Error message in the Cloudformation console

The interesting bit here is that the error message shows the AWS Account ID in addition to the Actual API ID. How do I resolve this?

Appreciate any help on this! Thanks in advance

Edit 1: apigateway import means how the API Gateway class methods are imported. AWS Cloudformation has two Resource Groups:

  • AWS::APIGateway
  • AWS::APIGatewayV2

Both of them have different capabilities. In older versions of the AWS CDK (v1.x), you had to import both the resource groups separately:

Old: import * as apigateway from '@aws-cdk/aws-api-gateway';

New: import * as apigatewayv2 from '@aws-cdk/aws-api-gatewayv2';

The newer CDK has brought everything together and can be written simply as:

import * as cdk from 'aws-cdk-lib';

// Call to v1 Resource Group:
const api = new cdk.aws_apigateway.RestApi(...);

// Call to v2 Resources:
const apiv2 = new cdk.aws_apigatewayv2.CfnRestApi(...);
1 Answers

I checked the cloudformation UI Console to trace the stack update and found that the Cfn Template generated by the ApiGatewayV2 Module was appending the Account Id in front of the API Id.

So I stopped using it and continued using the main CDK Import for API Gateway. Below is the code snippet that worked. I also had to manipulate a private variable for API Gateway Stage Deployment.

// ...

export class CustomApiGatewayIntegration extends constructs.Construct {
  constructor(scope: constructs.Construct, id: string, props: IApiGatewayIntegrationProps) {
    super(scope, id);

    const api = cdk.aws_apigateway.RestApi.fromRestApiAttributes(scope, 'api', {
      restApiId: props.restApiId,
      rootResourceId: props.restApiRootResourceId,
    });

    const vpcLink = cdk.aws_apigateway.VpcLink.fromVpcLinkId(this, 'vpc-link', props.VpcLink);

    const gatewayResource = api.root.addResource(props.apiPath);

    const endpoint = `http://${props.NLBDns}:${props.NLBPort}/${props.apiPath}`;

    const proxyResource = gatewayResource.addProxy({
      anyMethod: true,
      defaultIntegration: new cdk.aws_apigateway.Integration({
        type: cdk.aws_apigateway.IntegrationType.HTTP_PROXY,
        integrationHttpMethod: 'ANY',
        uri: `${endpoint}/{proxy}`,
        options: {
          vpcLink,
          connectionType: cdk.aws_apigateway.ConnectionType.VPC_LINK,
        },
      })
    });

    const deployment = new cdk.aws_apigateway.Deployment(this, 'api-deployment-' + new Date().toISOString(), { api });
    
    // Private member manipulation
    (deployment as any).resource.stageName = 'api';

    // Forcing dependency of deployment on the `proxyResource`
    // for sequential deployment in cloudformation
    deployment.node.addDependency(proxyResource);

    new CfnOutput(this, 'ServiceEndpoint', {
      value: endpoint,
      description: `Endpoint for ${props.appName} microservice`,
      exportName: `${props.org}-${props.environment}-service-endpoint`
    });
  }
}

// ...
Related