Creating Serverless Backend using AWS Lambda and DynamoDB

Mon, Oct 29, 2018 3-minute read

In this post I’m going to show how to create Lambda function for creating and showing items on DynamoDB.

Our diagram looks like this basically.

First of all we need to create our dynamodb table. I created using java sdk with these codes. This codes can be found in aws documentation.

Changed provisioned resources to 1 because yeah we just trying these no need much space.

public void createTable(String name) {
        CreateTableRequest request = new CreateTableRequest()
                .withAttributeDefinitions(new AttributeDefinition(
                        "Name", ScalarAttributeType.S))
                .withKeySchema(new KeySchemaElement("Id", KeyType.HASH))
                .withProvisionedThroughput(new ProvisionedThroughput(
                        new Long(1), new Long(1)))
                .withTableName(name);

        final AmazonDynamoDB ddb = AmazonDynamoDBClientBuilder.defaultClient();

        try {
            CreateTableResult result = ddb.createTable(request);
        } catch (AmazonServiceException e) {
            System.err.println(e.getErrorMessage());
            System.exit(1);
        }

    }

Since DynamoDB is nosql database i also created a model for future items. Table is simple we have person name,surname and addresses

package model;

import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;

import java.util.List;

@DynamoDBTable(tableName = "personTable")
public class Person {
    private String id;
    private String name;
    private String surname;
    private List<String> addresses;

    @DynamoDBHashKey(attributeName = "Id")
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    @DynamoDBAttribute(attributeName = "name")
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @DynamoDBAttribute(attributeName = "surname")
    public String getSurname() {
        return surname;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }

    @DynamoDBAttribute(attributeName = "addresses")
    public List<String> getAddresses() {
        return addresses;
    }

    public void setAddresses(List<String> addresses) {
        this.addresses = addresses;
    }
}

Add item function :

import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
import com.amazonaws.services.dynamodbv2.model.ResourceNotFoundException;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import model.Person;

public class LambdaMain implements RequestHandler<Person,String> {

    public String handleRequest(Person person, Context context) {

        final AmazonDynamoDB ddb = AmazonDynamoDBClientBuilder.defaultClient();
        final DynamoDBMapper mapper = new DynamoDBMapper(ddb);
        try {
            mapper.save(person);
        } catch (ResourceNotFoundException e) {
            System.exit(1);
        } catch (AmazonServiceException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
        return "OK";
    }

}

Lets invoke this function on lambda console

Yes i know you cant find james holden on Earth, maybe we should write Rocinante :).

{
  "id": "f01349dd-332d-4937-b3ae-9b50b995d2ef",
  "name": "James",
  "surname": "Holden",
  "addresses": ["Earth"]
}

Show item function:

import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBScanExpression;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import model.Person;

import java.util.List;
import java.util.Map;

public class LambdaMain implements RequestHandler<Map<String,Object>,List<Person>> {

    public List<Person> handleRequest(Map<String,Object> input, Context context) {

        final AmazonDynamoDB ddb = AmazonDynamoDBClientBuilder.defaultClient();
        final DynamoDBMapper mapper = new DynamoDBMapper(ddb);
        List<Person> personList = null;
        try {
            personList = mapper.scan(Person.class, new DynamoDBScanExpression());
        } catch (Exception e) {
            System.err.println(e.getMessage());
            System.exit(1);

        }
        return personList;
    }
}

Lets deploy and test this show method.

Created new stage as prod on apigateway and publish my methods there. Apigateway gave me a link for execute methods.

webischia@aws:~$ curl https://57l5o766j7.execute-api.us-west-2.amazonaws.com/prod/ | jq
  {
    "id": "1",
    "name": "lambda",
    "surname": "aws"
  },
  {
    "id": "234c1579-6cb4-4488-aa69-961c49a7736b",
    "name": "Fahri",
    "surname": "YARDIMCI",
    "addresses": [
      "Turkey"
    ]
  },
  {
    "id": "4b591dff-7c1d-41c9-8e4a-8d1f57c52cfd",
    "name": "Jeff",
    "surname": "Bezos",
    "addresses": [
      "Earth",
      "Mars",
      "Belt"
    ]
  },
  {
    "id": " f01349dd-332d-4937-b3ae-9b50b995d2ef",
    "name": "James",
    "surname": "Holden",
    "addresses": [
      "Earth"
    ]
  }
]

Conclusion:

Creating serverless backend easily with lambda is so much fun and so fast. You dont even think about servers/security(infra).