Serverless Framework: Setting up a custom domain to API Gateway

Serverless Framework: Setting up a custom domain to API Gateway

Adding a meaningful domain name for API Gateway using serverless configuration.

When we deploy our APIs using the Serverless Framework, it provides endpoints like, https://api-id.execute-api.region.amazonaws.com/stage. By using a custom domain we can make the endpoint name much more meaningful.

before-after-custom-domain.png

According to AWS docs,

Custom domain names are simpler and more intuitive URLs that you can provide to your API users.

With Serverless Framework, it is very easy and straightforward to set up a custom domain by adding some configuration in our serverless.yml file.

Prerequisite

Before we go further, we have to ensure,

  • AWS CLI is installed in local machine
  • Serverless framework is installed in local machine
  • Node.js v12.13.0 in installed in local machine
  • A hosted zone is setup Route 53 with a domain
  • An SSL certificate is installed for the domain and its sub-domains

Create a Sample Project

We will use a popular serverless-typescript boilerplate. First, create a project,

serverless install --url https://github.com/AnomalyInnovations/serverless-typescript-starter --name my-serverless-project

Go to the project root directory and install the dependencies,

cd my-serverless-project
npm install

Update the region from the serverless.yml file. Since, I am in ap-south-1 region, in my case, under provider the region should be ap-south-1.

Deploy the project to AWS by,

sls deploy

As output, we should get an endpoint like, https://9pmx5phid6.execute-api.region-name.amazonaws.com/dev/hello

stack-output.png

If we go to the link, we will see a success message that indicates, out API and lambda function is working.

raw-endpoint-output.png

Creating Custom Domain

To create a custom domain using the serverless framework, we will need a plugin named serverless-domain-manager.

Install the serverless-domain-manager in the project as a dev dependency,

npm install -D serverless-domain-manager

Now add the plugin to the serverless.yml file.

plugin.png

Now, we have to create a new section in the serverless.yml file, named custom,

custom:
  customDomain:
    domainName: my-sub-domain.my-domain.com
    basePath: "v1"
    stage: ${self:provider.stage}
    certificateName: original-domain
    createRoute53Record: true

Here,

domainName, the new domain name, that will replace the arbitrary auto created endpoint.

basePath, This will replace the stage name.

stage, This is the stage name, will be replaced by API version or basePath.

certificateName, SSL certified domain or sub-domain

createRoute53Record, Will automatically create a record in the hosted zone in Route53

Our final serverless.yml file should be very much be like the following,

service: host-service

package:
  individually: true

plugins:
  - serverless-bundle # Package our functions with Webpack
  - serverless-offline
  - serverless-dotenv-plugin # Load .env as environment variables
  - serverless-domain-manager

provider:
  name: aws
  runtime: nodejs12.x
  stage: dev
  region: ap-south-1

functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: hello
          method: get

custom:
  customDomain:
    domainName: host-api.my-tour-assistant.com
    basePath: "v1"
    stage: ${self:provider.stage}
    certificateName: my-tour-assistant.com
    createRoute53Record: true

Create the domain,

sls create_domain

Now deploy the app again and it will do the mapping,

sls deploy

After deployment is completed, if we go to the https://domainName/basePath/hello, we should see the success message as JSON format as expected.

new-url-domain.png

In my case, the new URL becomes https://host-api.my-tour-assistant.com/v1/hello.

Our custom domain is now integrated with the API-Gateway.

Handle Multiple Stage with Serverless Domain Manager

There could be a scenario, where we want to do the mapping for the production and development environment.

We want to run the dev API in dev.domainName/basePath and prod API in domainName/basePath.

In this case, our custom section of the serverless.yml file should be,

custom:
  domain:
    dev: tour-api-dev.my-tour-assistant.com
    prod: tour-api.my-tour-assistant.com
  customDomain:
    domainName: ${self:custom.domain.${opt:stage, 'dev'}}
    basePath: "v1"
    stage: ${self:provider.stage}
    certificateName: my-tour-assistant.com
    createRoute53Record: true

In this case, when we create the domain, we have to specify the stage. For example, create domain,

sls create_domain --stage dev # for dev API
sls create_domain --stage prod # for prod API

Similarly, when we deploy the app to AWS, we have to specify the stage also,

SLS_DEBUG=* sls deploy --stage dev -v # Deploy the app to the development environment
sls deploy --stage prod -v # Deploy the app to the production environment

For any queries or clarifications, please let me know.

For more AWS articles, take a look at my AWS Series.

References