[][src]Crate serde_dynamo

DynamoDB is an AWS database that stores key/value and document data.

The most common way to access DynamoDB data from Rust is to use rusoto_dynamodb's get_item, put_item, and related methods.

serde_dynamo provides a way to serialize and deserialize between data stored in these Items and strongly-typed Rust data structures.

The full power of serde

serde_dynamo supports the full power of serde.

Most uses of DynamoDB will involve simple structs mapping keys to values in type-safe ways.

#[derive(Serialize, Deserialize)]
pub struct User {
    id: String,
    name: String,
    age: u8,
}

More advanced usage – including flattening, adjacently tagged enums, and untagged enums – is fully supported.

#[derive(Serialize, Deserialize)]
struct Message {
    id: String,
    #[serde(flatten)]
    message_type: MessageType,
    sent: DateTime<Utc>,
}

/// What type of message this is.
///
/// By the power of Rust enums and serde serializating, we can guarantee that we _either_ have
/// an email with all of its required fields, _or_ an SMS with all of its required fields.
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "snake_case", tag = "message_type", content = "message_payload")]
enum MessageType {
    Email(Email),
    Sms(Sms),
}

#[derive(Serialize, Deserialize)]
struct Email {
    email: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    name: Option<String>,
    subject: String,
    body: String,
}

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
struct Sms {
    phone_number: String,
    body: String,
}

let input = r#"
{
    "id": "HWCqBFBG2Gl4",
    "message_type": "sms",
    "message_payload": {
        "phone_number": "5551234567",
        "body": "Good morning!"
    },
    "sent": "1985-04-21T11:12:13Z"
}
"#;
let message: Message = serde_json::from_str(input)?;
let item = to_item(message)?;

Parsing items as strongly-typed data structures.

Items received from a rusoto_dynamodb call can be run through from_item.

#[derive(Serialize, Deserialize)]
pub struct User {
    id: String,
    name: String,
    age: u8,
};

// Get documents from DynamoDB
let input = ScanInput {
    table_name: "users".to_string(),
    ..ScanInput::default()
};
let result = client.scan(input).await?;

// And deserialize them as strongly-typed data structures
for item in result.items.unwrap() {
    let user: User = from_item(item)?;
    println!("{} is {}", user.name, user.age);
}

Creating items by serializing data structures

Writing an entire data structure to DynamoDB typically involves using to_item to serialize it.

#[derive(Serialize, Deserialize)]
pub struct User {
    id: String,
    name: String,
    age: u8,
};

// Create a user
let user = User {
    id: "fSsgVtal8TpP".to_string(),
    name: "Arthur Dent".to_string(),
    age: 42,
};

// Turn it into an item that rusoto understands
let item = to_item(user)?;

// And write it!
let input = PutItemInput {
    table_name: "users".to_string(),
    item: item,
    ..PutItemInput::default()
};
client.put_item(input).await?;

Using to_attribute_value for more control

In some circumstances, building rusoto_dynamodb::AttributeValues directly is required.

For example, when generating a key to supply to get_item.

use maplit::hashmap;
use serde_dynamo::to_attribute_value;

// Create the unique key of the record in DynamoDB in a way rusoto understands
let key = hashmap! {
    "id".into() => to_attribute_value(&user.id)?,
};

// And get the record
let input = GetItemInput {
    table_name: "users".to_string(),
    key: key,
    ..GetItemInput::default()
};
client.get_item(input).await?;

Or when generating attribute values in a query call.

use maplit::hashmap;
use serde_dynamo::to_attribute_value;

// Declare all of the expression inputs for a query call
let expression_attribute_values = hashmap! {
    ":user_type".to_string() => to_attribute_value(user_type)?,
    ":last_login".to_string() => to_attribute_value(yesterday)?,
};

// And execute the query
let input = QueryInput {
    table_name: "users".to_string(),
    index_name: Some("by_type_and_last_login".to_string()),
    key_condition_expression: Some("user_type = :user_type AND last_login > :last_login".to_string()),
    expression_attribute_values: Some(expression_attribute_values),
    ..QueryInput::default()
};
client.query(input).await?;

JSON

DynamoDB's items share strong similarities with JSON, and it is very common to store JSON data in DynamoDB either directly or as a subfield.

To support this, serde_dynamo supports serializing JSON just like any other Rust data structure.

#[derive(Serialize, Deserialize)]
struct IncludesJson {
    id: String,
    data: serde_json::Value,
}

In addition, serde_dynamo also maps strongly-typed data structures nearly identically as serde_json. This means that, in almost all cases, serializing to JSON first and then to an Item will result in the exact same representation as serializing directly to an Item. (The caveat here is for byte data, which loses fidelity because JSON doesn't support byte data natively, but DynamoDB does.)

let user = User {
    name: "Arthur Dent".to_string(),
    age: 42,
};

// Serialize directly from the data structure to an item
let direct_item = to_item(user.clone())?;

// Serialize indirectly through JSON
let json = serde_json::to_value(user.clone())?;
let indirect_item = to_item(json)?;

// The result should be the same!
assert_eq!(direct_item, indirect_item);

Structs

Deserializer

A structure that deserializes AttributeValues into Rust values.

Error

This type represents all possible errors that can occur when serializing or deserializing DynamoDB data.

Serializer

A structure for serializing Rust values into AttributeValues.

Functions

from_attribute_value

Interpret a rusoto_dynamodb::AttributeValue as an instance of type T.

from_item

Interpret an Item as an instance of type T.

to_attribute_value

Convert a T into a rusoto_dynamodb::AttributeValue which is rusoto's representation of a DynamoDb value.

to_item

Convert a T into an Item which is rusoto_dynamodb's representation of a DynamoDb item.

Type Definitions

Item

An "Item" used in rusoto_dynamodb's get_item, write_item, put_item, etc.

Result

Alias for a Result with the error type serde_dynamo::Error