AWS API Developer Portal Tips

8 min read

So you have a need for an API Developer Portal in AWS 🙂

You’ll have no doubt found the AWS Serverless Application in the registry for this as mentioned https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-developer-portal.html

Couple of things that are obscure with this solution:

  1. How to deploy it multiple times in the same account
  2. How to do cross account API discovery
  3. How to use a custom domain name when deploying API Developer Portal
  4. How to do non ACM created Certs (Externally Signed)
  5. How to makes a group of APIs available to a subset of users

1. How to deploy it multiple times in the same account

This turns out to be impossible when deploying via the Serverless Application Repository. The name of the app is the name of the stack when creating the app twice off the SAR you will just end up doing a stack update instead..

Instead, you will need to deploy using the SAM method and create multiple stacks.

The documentation shows how to do it using this method. However, there is a third method also but this does not work as shown below:

Clicking the Copy as SAM Resource button lets you build your own cloudformation template to create a new stack that nests a SAR App using AWS::Serverless::Application.

You will need to modify this puppy if you are deploying twice as you will need to set table names and pool names to be unique.

Here is a version I created that may be of use to you:

---
Transform: AWS::Serverless-2016-10-31

Description: "API Developer Portal"

Parameters:
  pArtifactsS3BucketName:
    Type: String
    Description: Bucket Name for Artifacts

  pDevPortalSiteS3BucketName:
    Type: String
    Description: Bucket Name for the Web Site Code
    
  pCognitoDomainNameOrPrefix:
    Type: String
    Description: This string is used with the Amazon Cognito hosted UI for user sign-up and sign-in. Specify a unique domain name or prefix string.

  pDevPortalCustomersTableName:
    Type: String
    Description: Give a unique name for the customer table for the web app to use
    Default: DevPortalCustomers1

  pDevPortalFeedbackTableName:
    Type: String
    Description: Give a unique name for the feedback table for the web app to use
    Default: DevPortalFeedback1
  
  pCognitoIdentityPoolName:
    Type: String
    Description: Give a unique name for the Cognito Identity Pool for the web app to use
    Default: DevPortalIdentityPool1
  
  pCustomDomainName:
    Type: String
    Description: Custom Domain Name To Use. Leave blank to create a developer portal without a custom domain name. Standing up a developer portal stack with a custom domain name will take significantly longer than without.
  
  pCustomDomainNameAcmCertArn:
    Type: String
    Description: If you provided a domain name associated with an acm cert, then you must also specify here the acm cert's arn. us-east-1 region for cloudfront.

  pDevPortalAdminEmail:
    Type: String
    Description: Enter to override default. 
  
  pDevelopmentMode:
    Type: String
    Description: Enter to override default. 
    Default: false
    AllowedValues:
      - false
      - true
    
  pMarketplaceSubscriptionTopicProductCode:
    Type: String
    Description: Enter to override default. 
    Default: DevPortalMarketplaceSubscriptionTopic1
  
  pStaticAssetRebuildMode:
    Type: String
    Description: Leave blank or use overwrite-content By default, a static asset rebuild doesn't overwrite custom-content. Provide the value `overwrite-content` to replace the custom-content with your local version. Don't do this unless you know what you're doing -- all custom changes in your s3 bucket will be lost.
  
  pStaticAssetRebuildToken:
    Type: String
    Description: Provide a token different from the last deployment's token to re-upload the dev portal site's static assets. i.e. perform an upgrade from the github repo.
    Default: 1
  
  pUseRoute53Nameservers:
    Type: String
    Description: Enter to override default. 
    Default: false
    AllowedValues:
      - false
      - true
  
Resources:
  rAPIGatewayDevPortalApp:
    Type: AWS::Serverless::Application
    Properties:
      Location:
        ApplicationId: arn:aws:serverlessrepo:us-east-1:563878140293:applications/api-gateway-dev-portal
        SemanticVersion: 3.0.3
      Parameters: 
        # The S3 bucket in which the Open API documents are stored. Bucket names are globally unique, so you must change this.
        ArtifactsS3BucketName: !Ref pArtifactsS3BucketName
        # The Domain Name (or Prefix) at which your Cognito Hosted UI is located. This should be regionally unique.
        CognitoDomainNameOrPrefix: !Ref pCognitoDomainNameOrPrefix
        # The name for your Cognito Identity Pool.
        CognitoIdentityPoolName: !Ref pCognitoIdentityPoolName
        # Optionally provide a custom domain name associated with an ACM cert to create a developer portal at that domain name (provide with the format foo.bar.net). Leave blank to create a developer portal without a custom domain name. Standing up a developer portal stack with a custom domain name will take significantly longer than without.
        CustomDomainName: !Ref pCustomDomainName
        # If you provided a domain name associated with an acm cert, then you must also specify here the acm cert's arn. Leave this blank to create a developer portal without a custom domain name.
        CustomDomainNameAcmCertArn: !Ref pCustomDomainNameAcmCertArn
        # The email address where user submitted feedback notifications get sent.
        DevPortalAdminEmail: !Ref pDevPortalAdminEmail
        # The name of the DynamoDB Customers table.
        DevPortalCustomersTableName: !Ref pDevPortalCustomersTableName
        # The name of the DynamoDB table storing feedback submitted by users.
        DevPortalFeedbackTableName: !Ref pDevPortalFeedbackTableName
        # The S3 bucket in which the web application code is stored. Bucket names are globally unique, so you must change this.
        DevPortalSiteS3BucketName: !Ref pDevPortalSiteS3BucketName
        # Enabling this weakens security features (OAI, SSL, site S3 bucket with public read ACLs, Cognito callback verification, CORS, etc.) for easier development. It also breaks frontend routing (except to /index.html), including deep linking and page refresh. Do not enable this in production! Additionally, do not update a stack that was previously in development mode to be a production stack; instead, make a new stack that has never been in development mode.
        DevelopmentMode: !Ref pDevelopmentMode
        # The marketplace SNS topic suffix for subscription/unsubscription events
        MarketplaceSubscriptionTopicProductCode: !Ref pMarketplaceSubscriptionTopicProductCode
        # By default, a static asset rebuild doesn't overwrite custom-content. Provide the value `overwrite-content` to replace the custom-content with your local version. Don't do this unless you know what you're doing -- all custom changes in your s3 bucket will be lost.
        StaticAssetRebuildMode: !Ref pStaticAssetRebuildMode
        # Provide a token different from the last deployment's token to re-upload the dev portal site's static assets. You can provide a timestamp or GUID on each deployment to always re-upload the assets.
        StaticAssetRebuildToken: !Ref pStaticAssetRebuildToken
        # Only applicable if creating a custom domain name for your dev portal. Defaults to false, and you'll need to provide your own nameserver hosting. If set to true, a Route53 HostedZone and RecordSet are created for you.
        UseRoute53Nameservers: !Ref pUseRoute53Nameservers

If you don’t do this your second deployment will fail if you already have the SAR App deployed:

This also happens if you are using the “To download and deploy the serverless developer portal using AWS SAM” method.

2. How to do cross account API discovery

This is bad. There is no way to do this with the solution to date unless you fork and update the code yourself. Having a look through the 68 open issues and 20 odd pull requests none relate to this topic. I’m not willing to go there myself just yet 😉 so I guess the best we can do is deploy multiple portals for each account you have APIs within or develop a centralised API account perhaps one for Prod and one for NonProd and expose the APIs via 2 portals only.

3. How to use a custom domain name when deploying API Developer Portal

Already documented 🙂 How to use a custom domain name is mentioned here: https://aws.amazon.com/blogs/compute/deploying-a-personalized-api-gateway-serverless-developer-portal/ however it is a little glossed over. The github also has info under section Before going to production / Setup a custom domain for your Developer Portal

Things can get a little confusing when deploying the SAR app in regards to what bits of the form to fill out to enable a custom portal name. Should I be using true or false on the UseRoute53Nameservers setting? etc…

There are three parameters that control the custom naming of the portal:

  1. CognitoDomainNameOrPrefix 
  2. UseRoute53Nameservers
  3. CustomDomainNameAcmCertArn

The Certificate is not part of the creation process so you need to do this BEFORE you deploy.

From the docs: UseRoute53Nameservers is Only applicable if you’re creating a custom domain name for your developer portal. Specify true to skip creating a Route 53 HostedZone and RecordSet. You’ll need to provide your own name server hosting in place of Route 53. Otherwise, leave this field set to false.

So setting to true creates a hostedzone and a recordset false = you have to sort this out.

4. How to do non ACM created Certs (Externally signed)

This actually turns out to be pretty simple.

How to use a custom domain name is mentioned here: https://aws.amazon.com/blogs/compute/deploying-a-personalized-api-gateway-serverless-developer-portal/ and specifically calls out the need to create a cert.

As you can import certs into ACM and as the solution is only wanting the ACM ARN, you can specify an externally signed cert that you’ve imported.

5. How to make a set of APIs available to a subset of users via the Developer Portal

TL;DR: You can’t. Best you can do is make it private by modifying the cognito triggered lambda function.

Found in the docs on the github repo under Registering Users is this little gem:

If you intend for the developer portal to be ‘private’ to some group of users (and not globally / freely accessible), you will need to write a lambda function that enforces your business logic for user registration. Documentation on this lambda function’s use can be found here.

The link takes you to info on how a pre sign-up Lambda function is triggered just before Amazon Cognito signs up a new user.

So the answer to this question is. The SAR App by default does not handle this. You need to code up a custom aspect to the API Dev Portal to cater for this functionality.

Note: There is a trigger function already created with the build which just lets auto-registration for any user to occur. The docs said as much in the same paragraph in an earlier sentence. I double checked my deploy and sure enough there is a function set as a trigger on the cognito pool already. So you just need to update this function not make a new one. So what they really meant to say in the docs was this:

“If you intend for the developer portal to be ‘private’ to some group of users (and not globally / freely accessible), you will need to update the lambda function to include your business logic for user registration enforcement. “

Ok so with a custom lambda for enforcing a set of users maybe registered to a cognito group we can restrict users to the portal. But what about APIs to groups in the portal? No can do. One would have to update the core code of the portal to cope with GROUPS being sent down beyond “ADMIN”. The admin interface would have to define what APIs were available to what cognito groups and the user interface be updated to have controls embedded in the search and subscribe features. Having a look through the 68 open issues and 20 odd pull requests none relate to this topic. I’m not willing to go there myself just yet 😉 so I guess the best we can do is deploy multiple portals. Refer to points 1 and 2.