AWS Developer Tools Blog

Introducing DynamoDB Document API (Part 1)

Amazon DynamoDB has recently announced the support of storing entire JSON-style document as single DynamoDB items. What is as exciting is that the AWS SDK for Java has come up with a new Document API that makes it easy and simple to access all the feaures of Amazon DynamoDB, including the latest document support, but with less code!

The new Document API is designed from the ground up to be the next generation of API for accessing DynamoDB. It has an object-oriented API that provides full access to all the DynamoDB features including JSON data support, use of Document Path to access part of a document, new data types such as Map, List, etc.  The best part is, the resultant code is a lot less verbose, and is therefore both easier to write and read.

Alright, enough talking.  Perhaps the new API can best be illustrated with an example. Here I took the liberty of borrowing the code from a previous blog, Using Improved Conditional Writes in DynamoDB, and rewrite it using the new API. To begin with, the original code is copied here:

public static void main(String[] args) {
    // To run this example, first initialize the client, and create a table
    // named 'Game' with a primary key of type hash / string called 'GameId'.
    AmazonDynamoDB dynamodb; // initialize the client     
    try {
        // First set up the example by inserting a new item         
        // To see different results, change either player's
        // starting positions to 20, or set player 1's location to 19.
        Integer player1Position = 15;
        Integer player2Position = 12;
        dynamodb.putItem(new PutItemRequest()
                .withTableName("Game")
                .addItemEntry("GameId", new AttributeValue("abc"))
                .addItemEntry("Player1-Position",
                    new AttributeValue().withN(player1Position.toString()))
                .addItemEntry("Player2-Position",
                    new AttributeValue().withN(player2Position.toString()))
                .addItemEntry("Status", new AttributeValue("IN_PROGRESS")));
        // Now move Player1 for game "abc" by 1,
        // as long as neither player has reached "20".
        UpdateItemResult result = dynamodb.updateItem(new UpdateItemRequest()
            .withTableName("Game")
            .withReturnValues(ReturnValue.ALL_NEW)
            .addKeyEntry("GameId", new AttributeValue("abc"))
            .addAttributeUpdatesEntry(
                 "Player1-Position", new AttributeValueUpdate()
                     .withValue(new AttributeValue().withN("1"))
                     .withAction(AttributeAction.ADD))
            .addExpectedEntry(
                 "Player1-Position", new ExpectedAttributeValue()
                     .withValue(new AttributeValue().withN("20"))
                     .withComparisonOperator(ComparisonOperator.LT))
            .addExpectedEntry(
                 "Player2-Position", new ExpectedAttributeValue()
                     .withValue(new AttributeValue().withN("20"))
                     .withComparisonOperator(ComparisonOperator.LT))
            .addExpectedEntry(
                 "Status", new ExpectedAttributeValue()
                     .withValue(new AttributeValue().withS("IN_PROGRESS"))
                     .withComparisonOperator(ComparisonOperator.EQ))  
        );
        if ("20".equals(
            result.getAttributes().get("Player1-Position").getN())) {
            System.out.println("Player 1 wins!");
        } else {
            System.out.println("The game is still in progress: "
                + result.getAttributes());
        }
    } catch (ConditionalCheckFailedException e) {
        System.out.println("Failed to move player 1 because the game is over");
    }
}

Now, let’s rewrite the same code using the DynamoDB Document API:

public static void main(String[] args) {
    // Initialize the client and DynamoDB object
    AmazonDynamoDBClient client = new AmazonDynamoDBClient(...);
    DynamoDB dynamodb = new DynamoDB(client);

    try {
        Table table = dynamodb.getTable("Game");
        table.putItem(new Item()
            .withPrimaryKey("GameId", "abc")
            .withInt("Player1-Position", 15)
            .withInt("Player2-Position", 12)
            .withString("Status", "IN_PROGRESS"));
         
       UpdateItemOutcome outcome = table.updateItem(new UpdateItemSpec()
            .withReturnValues(ReturnValue.ALL_NEW)
            .withPrimaryKey("GameId", "abc")
            .withAttributeUpdate(
                new AttributeUpdate("Player1-Position").addNumeric(1))
            .withExpected(
                new Expected("Player1-Position").lt(20),
                new Expected("Player2-Position").lt(20),
                new Expected("Status").eq("IN_PROGRESS")));

        Item item = outcome.getItem();
        if (item.getInt("Player1-Position") == 20) {
            System.out.println("Player 1 wins!");
        } else {
            System.out.println("The game is still in progress: " + item);
        }
    } catch (ConditionalCheckFailedException e) {
        System.out.println("Failed to move player 1 because the game is over");
    }
}

As you see, the new Document API allows the direct use of plain old Java data types and has less boilerplate.  In fact, the Dynamo Document API can be used to entirely subsume what you can do with the low level client (i.e. AmazonDynamoDBClient) but with a much cleaner programming model and less code.

I hope this has whet your appetite in harnessing the power of Amazon DynamoDB using the Document API.  To see more examples, feel free to play with the code sample in the A-Z Document API quick-start folder at github, or check out the AWS blog.