Search code examples
amazon-web-servicesaws-api-gatewayaws-cdkaws-elbaws-cdk-typescript

Got Error "Either integrationSubtype` or `integrationUri` must be specified" when try to integration Fargate service with API gateway


I'm trying to create a public API which will be integrated with a Fargate service which already exists in private subnet.

I got below error when run cdk synthesize --profile=PandaService-Alpha.

/Users/yangliu/Projects/Panda/PandaApi/node_modules/@aws-cdk/aws-apigatewayv2-alpha/lib/http/integration.ts:249
      throw new Error('Either `integrationSubtype` or `integrationUri` must be specified.');
            ^
Error: Either `integrationSubtype` or `integrationUri` must be specified.
    at new HttpIntegration (/Users/yangliu/Projects/Panda/PandaApi/node_modules/@aws-cdk/aws-apigatewayv2-alpha/lib/http/integration.ts:249:13)
    at HttpAlbIntegration._bindToRoute (/Users/yangliu/Projects/Panda/PandaApi/node_modules/@aws-cdk/aws-apigatewayv2-alpha/lib/http/integration.ts:317:26)
    at new HttpRoute (/Users/yangliu/Projects/Panda/PandaApi/node_modules/@aws-cdk/aws-apigatewayv2-alpha/lib/http/route.ts:191:38)
    at /Users/yangliu/Projects/Panda/PandaApi/node_modules/@aws-cdk/aws-apigatewayv2-alpha/lib/http/api.ts:458:14
    at Array.map (<anonymous>)
    at HttpApi.addRoutes (/Users/yangliu/Projects/Panda/PandaApi/node_modules/@aws-cdk/aws-apigatewayv2-alpha/lib/http/api.ts:455:20)
    at ApigatewayStack.addApiRoutes (/Users/yangliu/Projects/Panda/PandaApi/lib/apigateway-stack.ts:110:22)
    at new ApigatewayStack (/Users/yangliu/Projects/Panda/PandaApi/lib/apigateway-stack.ts:101:10)
    at /Users/yangliu/Projects/Panda/PandaApi/bin/app.ts:17:3

The error is thrown in the addApiRoutes method in below code.

Code

import * as CDK from "aws-cdk-lib";

import * as CertificateManager from "aws-cdk-lib/aws-certificatemanager";
import * as Route53 from "aws-cdk-lib/aws-route53";
import * as ApiGatewayV2Alpha from "@aws-cdk/aws-apigatewayv2-alpha";
import * as ApiGatewayV2IntegrationsAlpha from "@aws-cdk/aws-apigatewayv2-integrations-alpha";

import * as ELBv2 from "aws-cdk-lib/aws-elasticloadbalancingv2";
import { Construct } from "constructs";
import { StageInfo } from "../config/stage-config";
import * as EC2 from "aws-cdk-lib/aws-ec2";

export interface ApigatewayStackProps extends CDK.StackProps {
  readonly packageName: string;
  readonly stageInfo: StageInfo;
}

export class ApigatewayStack extends CDK.Stack {
  private readonly coreVpc: EC2.IVpc;
  // Prefix for CDK constrcut ID
  private readonly constructIdPrefix: string;
  private readonly pandaApi: ApiGatewayV2Alpha.HttpApi;
  constructor(scope: Construct, id: string, props: ApigatewayStackProps) {
    super(scope, id, props);

    this.coreVpc = EC2.Vpc.fromLookup(
      this,
      `${props.stageInfo.stageName}VpcLookupId`,
      {
        vpcName: "CoreVpc",
      }
    );

    this.constructIdPrefix = `${props.packageName}-${props.stageInfo.stageName}`;

    const hostedZone: Route53.IHostedZone = Route53.HostedZone.fromLookup(
      this,
      `${this.constructIdPrefix}-HostedZoneLookup`,
      {
        domainName: props.stageInfo.domainName,
      }
    );
    const domainCertificate = new CertificateManager.Certificate(
      this,
      `${this.constructIdPrefix}-pandaApiCertificate`,
      {
        domainName: props.stageInfo.domainName,
        validation:
          CertificateManager.CertificateValidation.fromDns(hostedZone),
      }
    );
    const customDomainName = new ApiGatewayV2Alpha.DomainName(
      this,
      `${this.constructIdPrefix}-ApiGatewayDomainName`,
      {
        certificate: domainCertificate,
        domainName: props.stageInfo.domainName,
      }
    );

    this.pandaApi = new ApiGatewayV2Alpha.HttpApi(
      this,
      `${this.constructIdPrefix}-pandaApi`,
      {
        defaultDomainMapping: {
          domainName: customDomainName,
          //mappingKey: props.pipelineStageInfo.stageName
        },
        corsPreflight: {
          allowOrigins: ["*"],
          allowHeaders: ["*"],
          allowMethods: [
            ApiGatewayV2Alpha.CorsHttpMethod.OPTIONS,
            ApiGatewayV2Alpha.CorsHttpMethod.GET,
            ApiGatewayV2Alpha.CorsHttpMethod.POST,
            ApiGatewayV2Alpha.CorsHttpMethod.PUT,
          ],
          maxAge: CDK.Duration.hours(6),
        },
        //createDefaultStage: false,
        // only allow use custom domain
        disableExecuteApiEndpoint: true
      }
    );

    this.addApiRoutes(props);
  }

  /**
   * Add API routes for multiple services.
   */
  private addApiRoutes(props: ApigatewayStackProps) {
    const PandaServiceIntegration : ApiGatewayV2IntegrationsAlpha.HttpAlbIntegration =
      this.generatePandaServiceIntegration(props);
    this.pandaApi.addRoutes({
      path: "/products",
      methods: [ApiGatewayV2Alpha.HttpMethod.ANY],
      integration: PandaServiceIntegration,
    });
    this.pandaApi.addRoutes({
      path: "/store-categories",
      methods: [ApiGatewayV2Alpha.HttpMethod.ANY],
      integration: PandaServiceIntegration,
    });
    this.pandaApi.addRoutes({
      path: "/stores",
      methods: [ApiGatewayV2Alpha.HttpMethod.ANY],
      integration: PandaServiceIntegration,
    });
  }

  /**
   *
   * @returns HttpAlbIntegration for PandaService.
   */
  private generatePandaServiceIntegration(props: ApigatewayStackProps) {
    const vpcLink = new ApiGatewayV2Alpha.VpcLink(
      this,
      `${this.constructIdPrefix}-VpcLink`,
      {
        vpc: this.coreVpc,
        subnets: {
          subnetType: EC2.SubnetType.PRIVATE_ISOLATED,
        },
      }
    );

    const PandaServiceAlbSecurityGroup = EC2.SecurityGroup.fromLookupByName(
      this,
      `${this.constructIdPrefix}-PandaServiceAlbSecurityGroupLookup`,
      "PandaServiceAlbSecurityGroup",
      this.coreVpc
    );

    const PandaServiceAlbListener : ELBv2.IApplicationListener =
      ELBv2.ApplicationListener.fromApplicationListenerAttributes(this, `${this.constructIdPrefix}-PandaServiceAlbListenerLookUp`, {
        listenerArn: props.stageInfo.PandaServiceAlbArn,
        securityGroup: PandaServiceAlbSecurityGroup,
      });

    const PandaServiceIntegration: ApiGatewayV2IntegrationsAlpha.HttpAlbIntegration =
      new ApiGatewayV2IntegrationsAlpha.HttpAlbIntegration(
        `${this.constructIdPrefix}-PandaServiceIntegration`,
        PandaServiceAlbListener ,
        {
          method: ApiGatewayV2Alpha.HttpMethod.ANY,
          vpcLink: vpcLink,
          secureServerName: props.stageInfo.domainName,
          parameterMapping: new ApiGatewayV2Alpha.ParameterMapping()
        }
      );

    return PandaServiceIntegration;
  }
}



Solution

  • As Otavio pointed out, my props.stageInfo.PandaServiceAlbArn is an empty string, after updating it with the actual string the problem get resolved.