Colin Barker

Colin Barker

Cloud Solutions Architect and AWS Subject Matter Expert (SME)

Wishtrees and Serverless on AWS

Getting the Tokonatsu Virtual Matsuri Wishtree working on AWS

Colin Barker

4-Minute Read

The Tokonatsu Wish Tree

What is it?

During the COVID-19 Pandemic, Tokonatsu Festival needed to run a virtual online only event. One of the many ideas included the creation of a Virtual Portal with an online created Matsuri. This included a virtual version of our Japanese Virtual Wish Tree.

Photo by Lennart Jönsson (@lenjons) on Unsplash

Tanabata which is also known as the Star Festival, celebrates the meeting of the deities Orihime and Hikoboshi. A popular custom of this festival involves writing wishes on strips of paper. In modern times, these small bits of paper are hung on bamboo, or with Tokonatsu, our Wish Tree shrine.

This is where our Serverless Framework solution came from.

Background

The original code for the Tokonatsu Wish Tree was written by the Co-Vice Chair, Adam Hay. This used:

The code for which is available on the Tokonatsu GitHub under the WishTreeApplication.

Serverless Framework

An open-source framework that helps to easily build serverless applications on services like AWS. You use a combination of YAML and a CLI to control, manage, maintain, and operate your application.

Serverless Configuration File

This controlled from the serverless.yaml file within the api folder, and here is a quick breakdown of the file

service: toko-wishtree-api # Name of the serverless service
frameworkVersion: "2" # Framework version to use

provider: # Provider Block
  name: aws # Which cloud provider (AWS)
  runtime: nodejs12.x # Which Runtime (NodeJS12)
  lambdaHashingVersion: 20201221 # Used to remove depreciated options
  stage: ${opt:stage, 'dev'} # API Gateway Stage (defaults to dev)
  region: ${opt:region, 'eu-west-2'} # AWS Region (defaults to London)
  apiGateway: # Specific API Gateway config
    shouldStartNameWithService: true # Ensure the API GW service starts with this
# --snipped--

Here we setup the top level information for the serverless package. Setting up values including the service name, which is useful for identifying your deployment in AWS, and the framework version.

The provider section is where we start to define how the Serverless Framework will interact with the destination, and which specific codebase you are running. In this instance, we are using AWS with the NodeJS version of 12.x.

IAM Permissions

To ensure access to the DynamoDB table, we can define permissions in a new role which can be assigned to the Lambda functions. This will mean no specific IAM keys or credentials will be needed within the code.]

iam:
  role:
    statements:
      - Effect: "Allow"
        Action:
          - "dynamodb:GetItem"
          - "dynamodb:Scan"
          - "dynamodb:PutItem"
          - "dynamodb:UpdateItem"
        Resource:
          - arn:aws:dynamodb:*:*:table/${file(./config.${opt:stage, self:provider.stage, 'dev'}.json):WISH_TREE_TAGS_TABLE}

The Functions

Each API endpoint we need to define will need to have a function to go along with it. In this case, we can see the getTagsForWishTree function, that is used by the Javascript on the static site to collect a list of the current tags that it has stored in the DynamoDB table.

functions:
  getTagsForWishTree:
    name: wish-tree-${opt:stage, self:provider.stage, 'dev'}-get-tags
    handler: getTagsForWishTree.handler
    description: Function to get the Wishtree Tags from the DB
    environment:
      ENV: ${opt:stage, self:provider.stage, 'dev'}
      WISH_TREE_TAGS_TABLE: ${file(./config.${opt:stage, self:provider.stage, 'dev'}.json):WISH_TREE_TAGS_TABLE}
    events:
      - http:
          path: getTagsForWishTree
          method: get
          cors: true

This will generate two elements. The Lambda function using the NodeJS code with the filename getTagsForWishTree.js and will look for the handler function, as it’s entry point. The Lambda function then gets a set of environment variables called ENV and WISH_TREE_TAGS_TABLE which the latter contains the configured DynamoDB table name.

The events section defines what API Gateway should setup, in this instance the config asks for a path value of getTagsForWishTree using the HTTP method of GET, while also ensuring that the Cross-Origin Resource Sharing (CORS) headers are set. This ensures that browsers know which resources it should permit to be loaded, and which ones it shouldn’t.

The Resources

This is where we can get a little creative, as the Serverless Framework allows us to include other non-Serverless Framework resource as part of our deployment, beyond the usual Serverless technologies of Lambda and API Gateway.

resources:
  Resources:
    tagsTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: ${file(./config.${opt:stage, self:provider.stage, 'dev'}.json):WISH_TREE_TAGS_TABLE}
        AttributeDefinitions:
          - AttributeName: Description
            AttributeType: S
        KeySchema:
          - AttributeName: Description
            KeyType: HASH
        ProvisionedThroughput:
          ReadCapacityUnits: 5
          WriteCapacityUnits: 5
        SSESpecification:
          SSEEnabled: true

Here we can see the creation of our DynamoDB table with Server Side Encryption being enabled to ensure that the wish tree tags are secured for our use only. A small call out to the AWS Well-Architected Framework’s Security Pillar!

What about AWS CloudFront?

Typically an AWS API Gateway uses it’s own naming system and stage information to generate the API Endpoint, which takes the form of:

https://{restapi-id}.execute-api.{region}.amazonaws.com/{stageName}

This isn’t very friendly! With the use of Custom Domains we are able to choose our own user-friendly domain and map it to our API endpoint, finishing off the whole package.

The Custom Domain settings on API Gateway

Final Words

The full setup instructions on how to build your own Wishtree application are available on the WishTreeApplication repo on GitHub.

Recent Posts

Categories

About

A cloud solutions architect, AWS SME, geek, tinkerer, and geocacher.