Unlocking Serverless with AWS Lambda and IAM

As I mentioned earlier we find the code for our two Lambda functions create-user and get-user under their respective folders.

import json
import boto3
import os

client = boto3.client(‘dynamodb’)

table_name = os.getenv(“TABLE_NAME”)

def handler(event, _):
   body = json.loads(event[‘body’])

   data = client.put_item(
     TableName=table_name,
     Item={
        ‘id’: {
          ‘S’: body[‘id’]
        },
        ‘name’: {
          ‘S’: body[‘name’]
        }
   }
)
response = {
    ‘statusCode’: 200,
    ‘body’: json.dumps({“id”: body[‘id’], “name”:body[‘name’]}),
    ‘headers’: {
      ‘Content-Type’: ‘application/json’,
      ‘Access-Control-Allow-Origin’: ‘*’
    },
  }
  return response

import json
import boto3
import os

client = boto3.client(‘dynamodb’)
table_name = os.getenv(‘TABLE_NAME’)
def handler(event, _):

  data = client.get_item(
    TableName=table_name,
    Key={
      ‘id’: {
       ‘S’: event[‘pathParameters’][‘id’]
      }
  }
)

response = {
    ‘statusCode’: 200,
    ‘body’: json.dumps(data[‘Item’]),
    ‘headers’: {
      ‘Content-Type’: ‘application/json’,
      ‘Access-Control-Allow-Origin’: ‘*’
    },
}
return response

But the real core of a serverless project is the template file. This is where all the resources and configuration of your serverless architecture is defined.

AWSTemplateFormatVersion: “2010-09-09”
Transform: AWS::Serverless-2016-10-31
Description: >
  user-sam-app

  A sample user api

Globals:
  Function:
    Runtime: python3.9
    Timeout: 3
    Handler: app.handler
    Architectures:
      – x86_64
    Environment:
      Variables:
        TABLE_NAME: !Ref UserTable

Resources:
  CreateUserFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: create_user/
      Events:
        AccountsAPI:
         Type: Api
         Properties:
           Path: /users
           Method: post
      Policies:
        – DynamoDBWritePolicy:
               TableName: !Ref UserTable

GetUserFunction:
  Type: AWS::Serverless::Function
  Properties:
    CodeUri: get_user/
    Events:
     AccountsAPI:
      Type: Api
      Properties:
        Path: /users/{id}
        Method: get
    Policies:
        – DynamoDBReadPolicy:
               TableName: !Ref UserTable

UserTable:
  Type: AWS::DynamoDB::Table
  Properties:
    TableName: UserTable
    BillingMode: PAY_PER_REQUEST
    AttributeDefinitions:
      – AttributeName: id
        AttributeType: S
   KeySchema:
     – AttributeName: id
       KeyType: HASH

Outputs:
  UserAPI:
    Description: “API Gateway endpoint URL for Prod stage”
    Value: !Sub “https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/users/”

  CreateUserFunction:
    Description: “Create User Lambda Function ARN”
    Value: !GetAtt CreateUserFunction.Arn

  CreateUserFunctionIamRole:
    Description: “Implicit IAM Role created for Create User function”
    Value: !GetAtt CreateUserFunctionRole.Arn

  GetUserFunction:
    Description: “Get User Lambda Function ARN”
    Value: !GetAtt GetUserFunction.Arn

  GetUserFunctionIamRole:
    Description: “Implicit IAM Role created for the Get User function”
    Value: !GetAtt GetUserFunctionRole.Arn

  UserTable:
    Value: !Ref UserTable
    Description: DynamoDb Table to store users

It can definitely look intimidating at first but lets walk through each property to understand what each is accomplishing for us.

Globals:
  Function:
   Runtime: python3.9
   Timeout: 3
   Handler: app.handler
   Architectures:
     – x86_64
   Environment:
     Variables:
      TABLE_NAME: !Ref UserTable

Under Globals we can define properties for multiple resources at once. In this case each of the properties under Function apply to all Lambda functions defined in this file. Of note is the Handler which specifies the entry point for our functions and the Environment Variable TABLE_NAME which will be available to our functions to determine exactly which DynamboDB table to read and write from.

Under Resources you can define almost any AWS resource! Feel free to experiment!

Here we’ve created our two Lambda Functions with type AWS::Serverless::Function and our DynamoDB Table with type AWS::DynamoDB::Table.

Next, lets zoom in on our create-user Lambda function.

CreateUserFunction:
   Type: AWS::Serverless::Function
   Properties:
     CodeUri: create_user/
     Events:
       AccountsAPI:
         Type: Api
         Properties:
           Path: /users
           Method: post
     Policies:
      – DynamoDBWritePolicy:
        TableName: !Ref UserTable

Starting from the top, the Type AWS::Serverless::Function is actually a unique resource type provided by SAM that will implicitly create resources in order to help us quickly accomplish the Lambda configuration we saw earlier.

Read More HERE