diff --git a/services/search-index-lambda/Cargo.lock b/services/search-index-lambda/Cargo.lock
--- a/services/search-index-lambda/Cargo.lock
+++ b/services/search-index-lambda/Cargo.lock
@@ -43,9 +43,9 @@
 
 [[package]]
 name = "anyhow"
-version = "1.0.75"
+version = "1.0.79"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
+checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
 
 [[package]]
 name = "async-stream"
diff --git a/services/search-index-lambda/src/main.rs b/services/search-index-lambda/src/main.rs
--- a/services/search-index-lambda/src/main.rs
+++ b/services/search-index-lambda/src/main.rs
@@ -1,105 +1,22 @@
 use anyhow::{anyhow, Result};
 use lambda_runtime::{service_fn, Error, LambdaEvent};
 use reqwest::Response;
-use serde::{Deserialize, Serialize};
-use std::collections::HashMap;
+use serde::Serialize;
 use tracing::{self, Level};
 use tracing_subscriber::EnvFilter;
 
 mod constants;
+mod payload;
+mod query;
 
-#[derive(Deserialize, Serialize, Debug)]
-struct User {
-  #[serde(rename = "userID")]
-  user_id: String,
-  username: String,
-}
-
-#[derive(Serialize, Deserialize)]
-struct UpdateByQuery {
-  query: Query,
-
-  #[serde(skip_serializing_if = "Option::is_none")]
-  script: Option<Script>,
-}
-
-#[derive(Serialize, Deserialize)]
-struct Script {
-  source: String,
-  lang: String,
-}
-
-#[derive(Serialize, Deserialize)]
-struct Query {
-  #[serde(skip_serializing_if = "Option::is_none")]
-  r#match: Option<Match>,
-
-  #[serde(skip_serializing_if = "Option::is_none")]
-  term: Option<Term>,
-}
-
-#[derive(Deserialize, Serialize)]
-struct Match {
-  #[serde(rename = "userID")]
-  user_id: String,
-}
+use payload::{AttributeValue, EventPayload, OperationType, StreamRecord};
+use query::{Match, Query, Script, Term, UpdateByQuery};
 
-#[derive(Deserialize, Serialize)]
-struct Term {
+#[derive(Serialize, Debug)]
+pub struct User {
   #[serde(rename = "userID")]
-  user_id: String,
-}
-
-#[derive(Deserialize, Debug)]
-#[serde(rename_all = "UPPERCASE")]
-enum EventName {
-  Insert,
-  Modify,
-  Remove,
-}
-
-#[derive(Deserialize)]
-#[serde(rename_all = "PascalCase")]
-struct StreamRecord {
-  new_image: Option<HashMap<String, AttributeValue>>,
-  old_image: Option<HashMap<String, AttributeValue>>,
-}
-
-#[derive(Deserialize)]
-enum AttributeValue {
-  B(String),
-  Bool(bool),
-  BS(Vec<String>),
-  L(Vec<AttributeValue>),
-  M(HashMap<String, AttributeValue>),
-  N(String),
-  Ns(Vec<String>),
-  Null(bool),
-  S(String),
-  Ss(Vec<String>),
-  #[non_exhaustive]
-  Unknown,
-}
-
-#[derive(Deserialize, Debug)]
-#[serde(rename_all = "UPPERCASE")]
-enum OperationType {
-  Insert,
-  Modify,
-  Remove,
-}
-
-#[derive(Deserialize)]
-struct Record {
-  #[serde(rename = "eventName")]
-  event_name: Option<OperationType>,
-  dynamodb: Option<StreamRecord>,
-}
-
-#[derive(Deserialize)]
-struct EventPayload {
-  #[serde(rename = "Records")]
-  records: Vec<Record>,
+  pub user_id: String,
+  pub username: String,
 }
 
 #[tokio::main]
diff --git a/services/search-index-lambda/src/payload.rs b/services/search-index-lambda/src/payload.rs
new file mode 100644
--- /dev/null
+++ b/services/search-index-lambda/src/payload.rs
@@ -0,0 +1,54 @@
+use serde::Deserialize;
+use std::collections::HashMap;
+
+#[derive(Deserialize, Debug)]
+#[serde(rename_all = "UPPERCASE")]
+pub enum EventName {
+  Insert,
+  Modify,
+  Remove,
+}
+
+#[derive(Deserialize)]
+#[serde(rename_all = "PascalCase")]
+pub struct StreamRecord {
+  pub new_image: Option<HashMap<String, AttributeValue>>,
+  pub old_image: Option<HashMap<String, AttributeValue>>,
+}
+
+#[derive(Deserialize)]
+pub enum AttributeValue {
+  B(String),
+  Bool(bool),
+  BS(Vec<String>),
+  L(Vec<AttributeValue>),
+  M(HashMap<String, AttributeValue>),
+  N(String),
+  Ns(Vec<String>),
+  Null(bool),
+  S(String),
+  Ss(Vec<String>),
+  #[non_exhaustive]
+  Unknown,
+}
+
+#[derive(Deserialize, Debug)]
+#[serde(rename_all = "UPPERCASE")]
+pub enum OperationType {
+  Insert,
+  Modify,
+  Remove,
+}
+
+#[derive(Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct Record {
+  pub event_name: Option<OperationType>,
+  pub dynamodb: Option<StreamRecord>,
+}
+
+#[derive(Deserialize)]
+#[serde(rename_all = "PascalCase")]
+pub struct EventPayload {
+  pub records: Vec<Record>,
+}
diff --git a/services/search-index-lambda/src/query.rs b/services/search-index-lambda/src/query.rs
new file mode 100644
--- /dev/null
+++ b/services/search-index-lambda/src/query.rs
@@ -0,0 +1,36 @@
+use serde::Serialize;
+
+#[derive(Serialize)]
+pub struct UpdateByQuery {
+  pub query: Query,
+
+  #[serde(skip_serializing_if = "Option::is_none")]
+  pub script: Option<Script>,
+}
+
+#[derive(Serialize)]
+pub struct Script {
+  pub source: String,
+  pub lang: String,
+}
+
+#[derive(Serialize)]
+pub struct Query {
+  #[serde(skip_serializing_if = "Option::is_none")]
+  pub r#match: Option<Match>,
+
+  #[serde(skip_serializing_if = "Option::is_none")]
+  pub term: Option<Term>,
+}
+
+#[derive(Serialize)]
+pub struct Match {
+  #[serde(rename = "userID")]
+  pub user_id: String,
+}
+
+#[derive(Serialize)]
+pub struct Term {
+  #[serde(rename = "userID")]
+  pub user_id: String,
+}