diff --git a/services/comm-services-lib/src/database.rs b/services/comm-services-lib/src/database.rs
--- a/services/comm-services-lib/src/database.rs
+++ b/services/comm-services-lib/src/database.rs
@@ -98,42 +98,147 @@
   }
 }
 
+impl TryFromAttribute for String {
+  fn try_from_attr(
+    attribute_name: impl Into<String>,
+    attribute_value: Option<AttributeValue>,
+  ) -> Result<Self, DBItemError> {
+    match attribute_value {
+      Some(AttributeValue::S(value)) => Ok(value),
+      Some(_) => Err(DBItemError::new(
+        attribute_name.into(),
+        Value::AttributeValue(attribute_value),
+        DBItemAttributeError::IncorrectType,
+      )),
+      None => Err(DBItemError::new(
+        attribute_name.into(),
+        Value::AttributeValue(attribute_value),
+        DBItemAttributeError::Missing,
+      )),
+    }
+  }
+}
+
+impl TryFromAttribute for bool {
+  fn try_from_attr(
+    attribute_name: impl Into<String>,
+    attribute_value: Option<AttributeValue>,
+  ) -> Result<Self, DBItemError> {
+    match attribute_value {
+      Some(AttributeValue::Bool(value)) => Ok(value),
+      Some(_) => Err(DBItemError::new(
+        attribute_name.into(),
+        Value::AttributeValue(attribute_value),
+        DBItemAttributeError::IncorrectType,
+      )),
+      None => Err(DBItemError::new(
+        attribute_name.into(),
+        Value::AttributeValue(attribute_value),
+        DBItemAttributeError::Missing,
+      )),
+    }
+  }
+}
+
+impl TryFromAttribute for DateTime<Utc> {
+  fn try_from_attr(
+    attribute_name: impl Into<String>,
+    attribute: Option<AttributeValue>,
+  ) -> Result<Self, DBItemError> {
+    match &attribute {
+      Some(AttributeValue::S(datetime)) => datetime.parse().map_err(|e| {
+        DBItemError::new(
+          attribute_name.into(),
+          Value::AttributeValue(attribute),
+          DBItemAttributeError::InvalidTimestamp(e),
+        )
+      }),
+      Some(_) => Err(DBItemError::new(
+        attribute_name.into(),
+        Value::AttributeValue(attribute),
+        DBItemAttributeError::IncorrectType,
+      )),
+      None => Err(DBItemError::new(
+        attribute_name.into(),
+        Value::AttributeValue(attribute),
+        DBItemAttributeError::Missing,
+      )),
+    }
+  }
+}
+
+impl TryFromAttribute for HashMap<String, AttributeValue> {
+  fn try_from_attr(
+    attribute_name: impl Into<String>,
+    attribute_value: Option<AttributeValue>,
+  ) -> Result<Self, DBItemError> {
+    match attribute_value {
+      Some(AttributeValue::M(map)) => Ok(map),
+      Some(_) => Err(DBItemError::new(
+        attribute_name.into(),
+        Value::AttributeValue(attribute_value),
+        DBItemAttributeError::IncorrectType,
+      )),
+      None => Err(DBItemError::new(
+        attribute_name.into(),
+        Value::AttributeValue(attribute_value),
+        DBItemAttributeError::Missing,
+      )),
+    }
+  }
+}
+
+impl TryFromAttribute for Vec<u8> {
+  fn try_from_attr(
+    attribute_name: impl Into<String>,
+    attribute_value: Option<AttributeValue>,
+  ) -> Result<Self, DBItemError> {
+    match attribute_value {
+      Some(AttributeValue::B(data)) => Ok(data.into_inner()),
+      Some(_) => Err(DBItemError::new(
+        attribute_name.into(),
+        Value::AttributeValue(attribute_value),
+        DBItemAttributeError::IncorrectType,
+      )),
+      None => Err(DBItemError::new(
+        attribute_name.into(),
+        Value::AttributeValue(attribute_value),
+        DBItemAttributeError::Missing,
+      )),
+    }
+  }
+}
+
+#[deprecated = "Use `String::try_from_attr()` instead"]
 pub fn parse_string_attribute(
   attribute_name: impl Into<String>,
   attribute_value: Option<AttributeValue>,
 ) -> Result<String, DBItemError> {
-  match attribute_value {
-    Some(AttributeValue::S(value)) => Ok(value),
-    Some(_) => Err(DBItemError::new(
-      attribute_name.into(),
-      Value::AttributeValue(attribute_value),
-      DBItemAttributeError::IncorrectType,
-    )),
-    None => Err(DBItemError::new(
-      attribute_name.into(),
-      Value::AttributeValue(attribute_value),
-      DBItemAttributeError::Missing,
-    )),
-  }
+  String::try_from_attr(attribute_name, attribute_value)
 }
 
+#[deprecated = "Use `bool::try_from_attr()` instead"]
 pub fn parse_bool_attribute(
   attribute_name: impl Into<String>,
   attribute_value: Option<AttributeValue>,
 ) -> Result<bool, DBItemError> {
-  match attribute_value {
-    Some(AttributeValue::Bool(value)) => Ok(value),
-    Some(_) => Err(DBItemError::new(
-      attribute_name.into(),
-      Value::AttributeValue(attribute_value),
-      DBItemAttributeError::IncorrectType,
-    )),
-    None => Err(DBItemError::new(
-      attribute_name.into(),
-      Value::AttributeValue(attribute_value),
-      DBItemAttributeError::Missing,
-    )),
-  }
+  bool::try_from_attr(attribute_name, attribute_value)
+}
+
+#[deprecated = "Use `DateTime::<Utc>::try_from_attr()` instead"]
+pub fn parse_datetime_attribute(
+  attribute_name: impl Into<String>,
+  attribute_value: Option<AttributeValue>,
+) -> Result<DateTime<Utc>, DBItemError> {
+  DateTime::<Utc>::try_from_attr(attribute_name, attribute_value)
+}
+
+#[deprecated = "Use `HashMap::<String, AttributeValue>::try_from_attr()` instead"]
+pub fn parse_map_attribute(
+  attribute_name: impl Into<String>,
+  attribute_value: Option<AttributeValue>,
+) -> Result<HashMap<String, AttributeValue>, DBItemError> {
+  attribute_value.attr_try_into(attribute_name)
 }
 
 pub fn parse_int_attribute<T>(
@@ -160,28 +265,6 @@
   }
 }
 
-pub fn parse_datetime_attribute(
-  attribute_name: impl Into<String>,
-  attribute_value: Option<AttributeValue>,
-) -> Result<DateTime<Utc>, DBItemError> {
-  if let Some(AttributeValue::S(datetime)) = &attribute_value {
-    // parse() accepts a relaxed RFC3339 string
-    datetime.parse().map_err(|e| {
-      DBItemError::new(
-        attribute_name.into(),
-        Value::AttributeValue(attribute_value),
-        DBItemAttributeError::InvalidTimestamp(e),
-      )
-    })
-  } else {
-    Err(DBItemError::new(
-      attribute_name.into(),
-      Value::AttributeValue(attribute_value),
-      DBItemAttributeError::Missing,
-    ))
-  }
-}
-
 /// Parses the UTC timestamp in milliseconds from a DynamoDB numeric attribute
 pub fn parse_timestamp_attribute(
   attribute_name: impl Into<String>,
@@ -203,25 +286,6 @@
   Ok(DateTime::from_utc(naive_datetime, Utc))
 }
 
-pub fn parse_map_attribute(
-  attribute_name: impl Into<String>,
-  attribute_value: Option<AttributeValue>,
-) -> Result<HashMap<String, AttributeValue>, DBItemError> {
-  match attribute_value {
-    Some(AttributeValue::M(map)) => Ok(map),
-    Some(_) => Err(DBItemError::new(
-      attribute_name.into(),
-      Value::AttributeValue(attribute_value),
-      DBItemAttributeError::IncorrectType,
-    )),
-    None => Err(DBItemError::new(
-      attribute_name.into(),
-      Value::AttributeValue(attribute_value),
-      DBItemAttributeError::Missing,
-    )),
-  }
-}
-
 pub fn parse_integer<T>(
   attribute_name: impl Into<String>,
   attribute_value: &str,