diegoddox
diegoddox

Reputation: 603

cdk api gateway route53 lambda custom domain name not working

Similar questions has been made but none of them were able to help me fix the issue that I'm facing. What I'm trying to do is to connect my api-gateway/lamnda function with a custom domain name and for some reason when calling the api/domain is not returning what I expected.

cdk version: 1.53.0

    const lambdaFunction = new lambda.Function(this, 'LambdaApi', {
      functionName: 'lambda-api',
      handler: 'lambda.handler',
      runtime: lambda.Runtime.NODEJS_12_X,
      code: new lambda.AssetCode(join(process.cwd(), '../api/dist')),
      memorySize: 128,
      timeout: cdk.Duration.seconds(5),
    })

    const zone = route53.HostedZone.fromLookup(scope, 'Zone', {
     'example.com',
     privateZone: false,
    })

    const certificate = certificatemanager.Certificate.fromCertificateArn(
     this,
     'Certificate',
     CERT_ARN,
    )

    const api = new apigateway.LambdaRestApi(this, 'LambdaApiGateway', {
      handler: lambdaFunction,
      proxy: true,
      endpointTypes: [apigateway.EndpointType.EDGE],
      defaultCorsPreflightOptions: {
        allowOrigins: apigateway.Cors.ALL_ORIGINS,
      },
      options: {
        restApiName: 'gateway-api',
        domainName: {
          domainName: 'api.example.com',
          certificate,
        },
        deployOptions: {
          stageName: 'prod',
          metricsEnabled: true,
          loggingLevel: apigateway.MethodLoggingLevel.INFO,
          dataTraceEnabled: true,
        },
      },
    })

    new route53.ARecord(this, 'CustomDomainAliasRecord', {
      zone,
      recordName: 'api',
      target: route53.RecordTarget.fromAlias(new targets.ApiGateway(api)),
    })

The deployment process works fine, a ARecord is created on route53 that is pointing to the api-gateway domain name, the api mappings is created as well pointing to prod as specified on stageName but when calling the domain name it doesn’t work but when calling the api-gateway endpoint it does.

api.example.com/ping returns healthy

{id}.execute-api.us-east-1.amazonaws.com/prod/ping returns the current date

Been researching but I'm not able to find out why the api.example.com/ping is not working

Upvotes: 0

Views: 2844

Answers (3)

Daniel
Daniel

Reputation: 389

I suspect the reason is that ping is a reserved word on cloudfront

Upvotes: 0

diegoddox
diegoddox

Reputation: 603

I fixed with cloudfront distribution, here is the code.

const api = new apigateway.LambdaRestApi(
  this,
  'lambda-api-gateway',
  {
    handler: lambdaFunction,
    proxy: true,
    endpointTypes: [apigateway.EndpointType.EDGE],
    defaultCorsPreflightOptions: {
      allowOrigins: apigateway.Cors.ALL_ORIGINS,
      allowMethods: apigateway.Cors.ALL_METHODS,
    },
    options: {
      restApiName: 'gateway-api',
      domainName: {
        domainName,
        certificate,
      },
      deployOptions: {
        stageName: props.stageName,
        metricsEnabled: true,
        loggingLevel: apigateway.MethodLoggingLevel.INFO,
        dataTraceEnabled: true,
      },
    },
  },
)

const distribution = new cloudfront.CloudFrontWebDistribution(
  this,
  'api-cloudfront-distribution',
  {
    defaultRootObject: '/',
    originConfigs: [
      {
        customOriginSource: {
          domainName: `${api.restApiId}.execute-api.${this.region}.${this.urlSuffix}`,
        },
        originPath: `/${props.stageName}`,
        behaviors: [
          {
            allowedMethods: cloudfront.CloudFrontAllowedMethods.ALL,
            isDefaultBehavior: true,
            forwardedValues: {
              cookies: {
                forward: 'all',
              },
              queryString: true,
            },
          },
        ],
      },
    ],
    enableIpV6: true,
    viewerCertificate: cloudfront.ViewerCertificate.fromAcmCertificate(
      certificate,
      {
        aliases: [domainName],
        securityPolicy: cloudfront.SecurityPolicyProtocol.TLS_V1,
        sslMethod: cloudfront.SSLMethod.SNI,
      },
    ),
  },
)

const zone = zoneFromLookUp(this, props.zoneDomainName)
const target = route53.RecordTarget.fromAlias(
  new targets.CloudFrontTarget(distribution),
)

new route53.ARecord(this, 'arecord-api', {
  zone,
  recordName: domainName,
  target,
})

Upvotes: 1

Del
Del

Reputation: 306

For the most part we've done what you are doing there, but after the zone and certificate creation we've got something like this:

const customDomain = new DomainName(this, 'customDomain', {
    domainName: 'api.example.com',
    certificate: certificate,
    endpointType: EndpointType.REGIONAL // yours may be Edge here
})

We also use basePathMapping so we don't have to use "dev|stg|prod" on the end of the domain.

new BasePathMapping(this, 'CustomBasePathMapping', {
    domainName: customDomain,
    restApi: api // again yours may differ here
})

Upvotes: 3

Related Questions