AWS API Gateway HttpAPI SAM Custom Domain Name Error

Viewed 781

I want to move my existing Rest API to HTTP API, and getting error in custom domain configuration. My SAM file for HTTP API is:

  resHttpApiGateway:
    Type: AWS::Serverless::HttpApi
    Properties:
      StageName: !Sub "${paramEnvironment}"
      CorsConfiguration:
        AllowOrigins:
          - "*"
        AllowHeaders:
          - Content-Type
          - X-Amz-Date
          - Authorization
          - X-Api-Key
          - correlation-object
        AllowMethods:
          - GET
          - POST
          - PUT
          - DELETE
      Auth:
        Authorizers:
          authTokenAuthorizer:
            AuthorizerPayloadFormatVersion: 1.0
            FunctionArn: !Ref paramLambdaAuthorizer
            Identity:
              Headers:
                - Authorization
              ReauthorizeEvery: 0
      Domain:
        EndpointConfiguration: REGIONAL
        DomainName: !If
          - condIsLocal
          - !Sub "dev.${paramBaseDomain}"
          - !Sub "${paramEnvironment}.${paramBaseDomain}"
        CertificateArn: arn:aws:acm:xxx
        Route53:
          HostedZoneId: xxx
        BasePath: "company-api"

Error I get in Cloudformation:

The domain name you provided already exists. (Service: AmazonApiGatewayV2; Status Code: 400; Error Code: BadRequestException; Request ID: ddba8c65-63de-4be4-9316-afd777e8b63f; Proxy: null)

Because I have an existing custom domain configured in API Gateway. Looks like it tries to create a custom domain name, is there a way to map HTTP API instance to an existing custom domain? For REST API I was using AWS::ApiGateway::BasePathMapping for mapping for this task, but cannot find HTTP API alternative.

2 Answers

I don't think there's a way to do this since this is a pretty radical change (internally) between the old REST APIs from API Gateway and the newer HTTP APIs.

In the old REST APIs custom domain names are always configured using a CloudFront distribution (even if that's not visible in the CloudFront UI) and in CloudFront, it is impossible to associate more than one distribution with the same CNAME. If I'm not mistaken, this is even true cross-account.

There might be a workaround using wildcard domains though I have no experience with this myself.

Depending on where the API is running and what the SLA requirements of the APIs are, it might be easier to simply have some downtime to ensure this change goes smoothly. In the case of downtime, don't forget to reduce your TTL value of the Route53 DNS entry beforehand so your new record will be propagated more quickly to all DNS caches.

(Edit) Turns out it is possible, as long as you're not using AWS SAM to create the mappings. Below is a shortened example from this source

[...]
Resources:
 [...]

  CustomDomainName: # Creates the domain name only
    Type: AWS::ApiGatewayV2::DomainName
    Properties: 
      DomainName: !Ref DomainName
      DomainNameConfigurations: 
        - EndpointType: REGIONAL
          CertificateArn: !If [CreateCert, !Ref GeneratedCert, !Ref CertArn]

  HttpApiMapping: # Create a mapping to an HTTP API (V2)
    Type: AWS::ApiGatewayV2::ApiMapping
    Properties: 
      ApiId: !Ref HttpApiGateway
      ApiMappingKey: http
      DomainName: !Ref CustomDomainName
      Stage: !Ref HttpApiGatewayApiGatewayDefaultStage ## = {LogicalName} + ApiGateway + {StageName} + Stage

  RestApiMapping: #Create a maooing to a REST API (V1)
    Type: AWS::ApiGatewayV2::ApiMapping
    Properties: 
      ApiId: !Ref RestApiGateway
      ApiMappingKey: rest
      DomainName: !Ref CustomDomainName
      Stage: !Ref RestApiGatewayProdStage ## = {Logicalname} + {StageName} + Stage

  HttpApiGateway: # Creates a HTTP API endpoint under the customm domian
    Type: AWS::Serverless::HttpApi

  RestApiGateway: # Creates a Rest API endpoint under the customm domian
    Type: AWS::Serverless::Api
    Properties:
      StageName: Prod
  [...]

  RecordSet: # Creates a record set in the hosted zone for custom domain to point at the APICustomDomain alias
    Type: AWS::Route53::RecordSet
    Properties:
      Name: !Ref DomainName
      HostedZoneId: !If [CreateZone, !Ref GeneratedZone, !Ref ZoneId]
      AliasTarget: 
        DNSName: !GetAtt CustomDomainName.RegionalDomainName
        HostedZoneId: !GetAtt CustomDomainName.RegionalHostedZoneId
      Type: A

You can use AWS::ApiGatewayV2::ApiMapping. It allows you to link an existing custom domain name to AWS::Serverless::HttpApi. You can use ApiMappingKey for your different path mappings (BasePath) as that's what SAM does under the hood.

Related