How to set up custom domain names for AppSync
Tags: appsync, aws, serverless, graphql
Published: 2020-09-13 00:45:14

---
title: How to set up custom domain names for AppSync
published: true
date: 2020-09-08 22:50:17 UTC
tags: AppSync,AWS,Serverless,GraphQL
canonical_url: https://theburningmonk.com/2020/09/how-to-set-up-custom-domain-names-for-appsync/
---

I previously wrote about [five reasons you should consider AppSync over API Gateway](https://lumigo.io/aws-serverless-ecosystem/aws-appsync-five-reasons-you-should-consider-it-over-api-gateway/). One thing that API Gateway supports but you can’t do with AppSync out-of-the-box yet is custom domain names.

Your shiny new AppSync API is available at `XYZ.appsync-api.us-east-1.amazonaws.com/graphql`, but you really want people to use your own domain instead because `dev.example.com/graphql` is much more memorable and informative.

In this post, let’s look at two ways you can do this.

### CloudFront

This is my preferred way. It’s **easy to set up and cheap to run**.

Assuming your AppSync API resource is called `GraphQlApi` (if you use the [serverless-appsync-plugin](https://github.com/sid88in/serverless-appsync-plugin) with the Serverless framework, then this is the logical id it’ll use). This is the CloudFormation resource you need to configure to route traffic to the AppSync API.

```
AppSyncDistribution:
  Type: AWS::CloudFront::Distribution
  Properties:
    DistributionConfig:
      Origins:
        - Id: AppSync
          DomainName:
            Fn::Select:
              - '2'
              - Fn::Split:
                  - "/"
                  - Fn::GetAtt:
                      - GraphQlApi
                      - GraphQLUrl
          CustomOriginConfig:
            HTTPPort: 80
            HTTPSPort: 443
            OriginProtocolPolicy: https-only
            OriginSSLProtocols:
              - TLSv1
              - TLSv1.1
              - TLSv1.2
          OriginPath: ''
      Enabled: true
      HttpVersion: http2
      Comment: CloudFront distribution for the Patient AppSync API
      Aliases:
        - <INSERT DOMAIN NAME HERE, e.g. dev.example.com>
      PriceClass: PriceClass_100
      DefaultCacheBehavior:
        AllowedMethods:
          - HEAD
          - OPTIONS
          - GET
          - DELETE
          - POST
          - PUT
          - PATCH
        CachedMethods:
          - HEAD
          - OPTIONS
          - GET
        ForwardedValues:
          QueryString: true
          Headers:
            - x-api-key
            - Authorization
          Cookies:
            Forward: all
        MinTTL: 0
        DefaultTTL: 0
        TargetOriginId: AppSync
        ViewerProtocolPolicy: redirect-to-https
        Compress: true
      CustomErrorResponses: []
      ViewerCertificate:
        AcmCertificateArn: <INSERT ARN HERE>
        SslSupportMethod: sni-only
```

If you’re using the [Serverless framework](https://www.serverless.com/open-source/), then you should also check out the [serverless-appsync-cloudfront](https://www.npmjs.com/package/serverless-appsync-cloudfront) plugin. It can make things a lot easier for you. However, at the time of writing, it makes assumptions about the logical Id of the AppSync API (it expects `GraphQlApi`) as it’s intended to used alongside the aforementioned `serverless-appsync-plugin`.

### API Gateway

Another way you can do this is through API Gateway. You can set up an HTTP proxy that routes traffic to the AppSync API, and then configure a custom domain name in API Gateway.

Compared to using CloudFront, this approach takes more work to set up and incurs higher cost and latency (compared to using CloudFront) because every request has to go through API Gateway.

If you’re using the Serverless framework, then another stumbling block is that you can’t _easily_ declare an API Gateway without any Lambda functions. Luckily, you can work around this by bringing SAM’s macro `AWS::Serverless-2016–10–31` into the `serverless.yml` like in [this post](https://dev.to/theburningmonk/how-to-include-serverless-repository-apps-in-serverless-yml-52md). This lets you configure API Gateway using SAM’s [AWS::Serverless::Api](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-api.html) resource type.

```
ApiGateway:
  Type: AWS::Serverless::Api
  Properties:
    Name: AppSyncApiProxy
    StageName: dev
    OpenApiVersion: "3.0.1"
    DefinitionBody:
      openapi: "3.0.1"
      paths:
        /{proxy+}:
          "x-amazon-apigateway-any-method":
            consumes:
              - "application/json"
            produces:
              - "application/json"
            parameters:
              - name: proxy
                in: path
                required: true
                type: string
            x-amazon-apigateway-integration:
              uri: 
                Fn::Join:
                  - ''
                  - - 'https://'
                    - Fn::Select:
                        - '2'
                        - Fn::Split:
                            - "/"
                            - Fn::GetAtt:
                                - GraphQlApi
                                - GraphQLUrl
                    - '/{proxy}'
              passthroughBehavior: when_no_match
              httpMethod: ANY
              type: http_proxy                  
              requestParameters:
                integration.request.path.proxy : method.request.path.proxy
    EndpointConfiguration: REGIONAL

ApiGatewayDomainName:
  Type: AWS::ApiGateway::DomainName
  Properties:
    DomainName: <INSERT DOMAIN NAME>
    EndpointConfiguration:
      Types:
        - REGIONAL
    RegionalCertificateArn: <INSERT ARN HERE>

ApiGatewayBasePathMapping:
  Type: AWS::ApiGateway::BasePathMapping
  DependsOn:
    - ApiGatewayDomainName
  Properties:
    DomainName: <INSERT DOMAIN NAME>
    RestApiId: !Ref ApiGateway
    Stage: !Ref ApiGateway.Stage
```

One thing to note here is that, by default, SAM creates an API Gateway stage called `Stage`. This appears to be a long-standing bug with SAM and the workaround is to set `OpenApiVersion` to `3.0.1`.

### Route53

As a final step for both of these approaches, you need to configure a Route53 record for them in your hosted zone.

For CloudFront, you need something like this:

![](https://theburningmonk.com/wp-content/uploads/2020/09/img_5f580a752bac3.png)

For API Gateway, you need to capture the `API Gateway domain name` for the custom domain (in API Gateway) and configure a Route53 record against it.

![](https://theburningmonk.com/wp-content/uploads/2020/09/img_5f580a8ccb333.png)

![](https://theburningmonk.com/wp-content/uploads/2020/09/img_5f580a964eb9d.png)

You can also configure these using CloudFormation.

### Summary

With both of these approaches, you can create a custom domain name (such as `dev.example.com`) for AppSync. Callers can access your AppSync API via `dev.example.com/graphql` which is much more user-friendly and memorable.

As mentioned above, I prefer the CloudFront approach because it’s easier to configure and has a negligible cost overhead.

If you want to learn GraphQL and AppSync with a hands-on tutorial then please check out my [**new AppSync course**](https://appsyncmasterclass.com/) where you will build a Twitter clone using a combination of AppSync, Lambda, DynamoDB, Cognito and Vue.js. You will learn about different GraphQL modelling techniques, how to debug resolvers, CI/CD, monitoring and alerting and much more.

![](https://theburningmonk.com/wp-content/uploads/2020/08/Screenshot-2020-08-26-at-14.53.39.png)