AWS Serverless Application Model YAML Templates: An Introduction

If you’ve never worked with YAML before, you’ll probably find the basic template format daunting. YAML — which somehow doesn’t stand for Yet Another Markdown Language, but instead YAML Ain’t Markdown Language — is a simplified way of storing data structures. YAML is popular with Rails users and sees some popularity with all higher order language programmers (JS, Python, etc…).

Clean, Simple Formatting

YAML is popular with languages that tend to see only three types of data:

  • Scalars: numbers and strings, the ‘text’ of your data
  • Heaps: e.g. objects, dictionaries, or any other term for a mapping of key-value pairs
  • Lists: i.e. arrays or an ordered sequence of the other two data types

YAML primarily tries to produce configuration documents that are readable without any special interpretation and formatting. If you look at even a short snippet of YAML from the middle of a SAM configuration file the key-value pairs are pretty readable, and you can even guess how lists might be used:

   DynamoDBTable:
     Type: AWS::DynamoDB::Table
     Properties:
       AttributeDefinitions:
         - AttributeName: id
           AttributeType: S

Indentation is used for structure, colons separate key-value pairs, and dashes are used to create “bullet” lists.

This simple, clean formatting also brings us to the most common complaint about YAML, it is whitespace-dependent, and missing a single tab can mess up the interpretation of the whole document.

YAML Basics

Always remember that YAML Lint is your friend. I still use yamllint.com every time I write YAML, turning on a display for invisible characters and purpose built linters for your IDE are all well and good, but that final check of YAML is still crucial.

YAML vs. XML

If you’re familiar with XML you may well have already interacted with systems that use either YAML or XML for configuration, or noticed that they are used by competing data storage systems. YAML is instantly readable, XML is not. On the other hand, the X in XML stands for “extensible” and while YAML really only has three ways to store data, the markup available in XML is limitless.

YAML vs. JSON

JavaScript Object Notation (JSON) and YAML look more similar and share design goals. While JSON is designed to be a bit easier to compile programmatically, the biggest difference for everyday use is that YAML has a method for referencing other items in the same JSON file. This might seem pretty minor but when standing up multiple API pathways in a SAM file, the ability to say TABLE_NAME: !Ref Table is a huge convenience.

The official specifications for YAML are well written and have some general guidance on best practices, implementation differences, and the design goals of YAML.

AWS Serverless Application Model

AWS CloudFormation templates are a standardized specification for describing, documenting, and deploying components of a serverless application Let’s look at one of the shortest possible SAM files:

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31

Resources:
    MyFirstFunction:
        Type: AWS::Serverless::Function
        Properties:
           Handler: index.handler
           Runtime: nodejs4.3
           CodeUri: s3://bucketName/codepackage.zip

With the Handler property set to index.handler, the code package at the CodeUri will be opened, CloudFormation will look for a file (“index”) and a function or module (“handler”). Both the AWSTemplateFormatVersion and Transform should be the same for all your Sam files, and the Type and Runtime properties are self-explanatory.

Events

While the template above will create a Lambda, it’ll be fundamentally incomplete since it needs something to trigger a Lambda in order to run. The Events property defines these triggers.

In general you’d use SAM files when you want to define multiple interlinked pieces of your application. This example (leaving off the top three lines that will be the same in every SAM file) grabs events from a DynamoDB table:

  TableAlerter:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.handler
      Runtime: nodejs6.10
      Events:
        Stream:
          Type: DynamoDB
          Properties:
            Stream: !GetAtt DynamoDBTable.StreamArn
            BatchSize: 100
            StartingPosition: TRIM_HORIZON  

Bringing it All Together

Most of the time SAM is the best choice because SAM can stand up an interlinked set of resources. So our SAM file will have more than one key under Resources.

Let’s stand up a table for the lambda above to read from:

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
  TableAlerter:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.handler
      Runtime: nodejs6.10
      Events:
        Stream:
          Type: DynamoDB
          Properties:
            Stream: !GetAtt DynamoDBTable.StreamArn
            BatchSize: 100
            StartingPosition: TRIM_HORIZON   

  Alerts:
    Type: AWS::DynamoDB::Table
    Properties:
      AttributeDefinitions:
        - AttributeName: id
          AttributeType: S
      KeySchema:
        - AttributeName: id
          KeyType: HASH
      ProvisionedThroughput:
        ReadCapacityUnits: 5
        WriteCapacityUnits: 5

At this point it might be helpful to use anchors from the YAML specification to share config information or try the AWS SAM system for creating and sharing environment variables.

The official AWS documentation on SAM isn’t particularly instructive, with just a few examples and some tutorial references. However the full specification is laid out in the AWSLabs GitHub project documentation.

Once you’ve mastered the basics, or if you’re feeling overwhelmed by the tool, you may want to use a service to create and deploy your stack via CloudFormation. Stackery does just that, and recently announced that Stackery now builds SAM templates natively.