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.
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;
}
}
As Otavio pointed out, my props.stageInfo.PandaServiceAlbArn
is an empty string, after updating it with the actual string the problem get resolved.