diff --git a/Cargo.lock b/Cargo.lock
index fc83ca8dac144532d4b929b59f7e6102925830f5..e10a154cd0fdff4194e09e64a348ccb96877e938 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -15,12 +15,6 @@ version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
 
-[[package]]
-name = "ahash"
-version = "0.4.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e"
-
 [[package]]
 name = "aho-corasick"
 version = "0.7.15"
@@ -245,18 +239,6 @@ version = "0.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
 
-[[package]]
-name = "bcrypt"
-version = "0.8.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2cab630912253fb9dc92c0e2fabd0a7b51f5a5a4007177cfa31e517015b7204"
-dependencies = [
- "base64 0.12.3",
- "blowfish",
- "byteorder",
- "getrandom",
-]
-
 [[package]]
 name = "binascii"
 version = "0.1.4"
@@ -319,15 +301,6 @@ dependencies = [
  "generic-array 0.14.4",
 ]
 
-[[package]]
-name = "block-cipher"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f337a3e6da609650eb74e02bc9fac7b735049f7623ab12f2e4c719316fcc7e80"
-dependencies = [
- "generic-array 0.14.4",
-]
-
 [[package]]
 name = "block-padding"
 version = "0.1.5"
@@ -351,17 +324,6 @@ dependencies = [
  "once_cell",
 ]
 
-[[package]]
-name = "blowfish"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f06850ba969bc59388b2cc0a4f186fc6d9d37208863b15b84ae3866ac90ac06"
-dependencies = [
- "block-cipher",
- "byteorder",
- "opaque-debug 0.3.0",
-]
-
 [[package]]
 name = "bson"
 version = "1.1.0"
@@ -396,16 +358,6 @@ version = "1.3.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
 
-[[package]]
-name = "bytes"
-version = "0.4.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c"
-dependencies = [
- "byteorder",
- "iovec",
-]
-
 [[package]]
 name = "bytes"
 version = "0.5.6"
@@ -985,7 +937,7 @@ version = "0.2.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5e4728fd124914ad25e99e3d15a9361a879f6620f63cb56bbb08f95abb97a535"
 dependencies = [
- "bytes 0.5.6",
+ "bytes",
  "fnv",
  "futures-core",
  "futures-sink",
@@ -1004,9 +956,6 @@ name = "hashbrown"
 version = "0.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
-dependencies = [
- "ahash",
-]
 
 [[package]]
 name = "heck"
@@ -1073,7 +1022,7 @@ version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "84129d298a6d57d246960ff8eb831ca4af3f96d29e2e28848dae275408658e26"
 dependencies = [
- "bytes 0.5.6",
+ "bytes",
  "fnv",
  "itoa",
 ]
@@ -1084,7 +1033,7 @@ version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b"
 dependencies = [
- "bytes 0.5.6",
+ "bytes",
  "http",
 ]
 
@@ -1115,7 +1064,7 @@ version = "0.13.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f6ad767baac13b44d4529fcf58ba2cd0995e36e7b435bc5b039de6f47e880dbf"
 dependencies = [
- "bytes 0.5.6",
+ "bytes",
  "futures-channel",
  "futures-core",
  "futures-util",
@@ -1139,7 +1088,7 @@ version = "0.21.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "37743cc83e8ee85eacfce90f2f4102030d9ff0a95244098d781e9bee4a90abb6"
 dependencies = [
- "bytes 0.5.6",
+ "bytes",
  "futures-util",
  "hyper",
  "log",
@@ -1155,7 +1104,7 @@ version = "0.4.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d979acc56dcb5b8dddba3917601745e877576475aa046df3226eabdecef78eed"
 dependencies = [
- "bytes 0.5.6",
+ "bytes",
  "hyper",
  "native-tls",
  "tokio",
@@ -1169,7 +1118,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2adce67e2c21cd95288ae3d9f2bbb2762cf17c03744628d49679f315ed1e2e58"
 dependencies = [
  "base64 0.13.0",
- "bytes 0.5.6",
+ "bytes",
  "http",
  "httparse",
  "httpdate",
@@ -1231,7 +1180,7 @@ version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "19a8a95243d5a0398cae618ec29477c6e3cb631152be5c19481f80bc71559754"
 dependencies = [
- "bytes 0.5.6",
+ "bytes",
 ]
 
 [[package]]
@@ -1322,12 +1271,6 @@ version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
-[[package]]
-name = "lazycell"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
-
 [[package]]
 name = "lettre"
 version = "0.10.0-alpha.4"
@@ -1390,15 +1333,6 @@ dependencies = [
  "cfg-if 0.1.10",
 ]
 
-[[package]]
-name = "lru"
-version = "0.6.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3aae342b73d57ad0b8b364bd12584819f2c1fe9114285dfcf8b0722607671635"
-dependencies = [
- "hashbrown",
-]
-
 [[package]]
 name = "lru-cache"
 version = "0.1.2"
@@ -1488,18 +1422,6 @@ dependencies = [
  "winapi 0.2.8",
 ]
 
-[[package]]
-name = "mio-extras"
-version = "2.0.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19"
-dependencies = [
- "lazycell",
- "log",
- "mio",
- "slab",
-]
-
 [[package]]
 name = "mio-uds"
 version = "0.6.8"
@@ -2295,7 +2217,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0718f81a8e14c4dbb3b34cf23dc6aaf9ab8a0dfec160c534b3dbca1aaa21f47c"
 dependencies = [
  "base64 0.13.0",
- "bytes 0.5.6",
+ "bytes",
  "encoding_rs",
  "futures-core",
  "futures-util",
@@ -2344,7 +2266,6 @@ version = "0.3.0-alpha"
 dependencies = [
  "async-std",
  "async-tungstenite",
- "bcrypt",
  "bitfield",
  "chrono",
  "ctrlc",
@@ -2356,13 +2277,13 @@ dependencies = [
  "lazy_static",
  "lettre",
  "log",
- "lru",
  "many-to-many",
  "mongodb",
  "num_enum",
  "once_cell",
  "rand 0.7.3",
  "rauth",
+ "regex",
  "reqwest",
  "rocket",
  "rocket_contrib",
@@ -2373,7 +2294,6 @@ dependencies = [
  "time 0.2.23",
  "ulid",
  "validator",
- "ws",
 ]
 
 [[package]]
@@ -3060,7 +2980,7 @@ version = "0.2.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "099837d3464c16a808060bb3f02263b412f6fafcb5d01c533d309985fbeebe48"
 dependencies = [
- "bytes 0.5.6",
+ "bytes",
  "fnv",
  "futures-core",
  "iovec",
@@ -3128,7 +3048,7 @@ version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499"
 dependencies = [
- "bytes 0.5.6",
+ "bytes",
  "futures-core",
  "futures-sink",
  "log",
@@ -3236,7 +3156,7 @@ checksum = "f0308d80d86700c5878b9ef6321f020f29b1bb9d5ff3cab25e75e23f3a492a23"
 dependencies = [
  "base64 0.12.3",
  "byteorder",
- "bytes 0.5.6",
+ "bytes",
  "http",
  "httparse",
  "input_buffer",
@@ -3648,24 +3568,6 @@ dependencies = [
  "winapi 0.3.9",
 ]
 
-[[package]]
-name = "ws"
-version = "0.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c51a2c47b5798ccc774ffb93ff536aec7c4275d722fd9c740c83cdd1af1f2d94"
-dependencies = [
- "byteorder",
- "bytes 0.4.12",
- "httparse",
- "log",
- "mio",
- "mio-extras",
- "rand 0.7.3",
- "sha-1 0.8.2",
- "slab",
- "url",
-]
-
 [[package]]
 name = "ws2_32-sys"
 version = "0.2.1"
diff --git a/Cargo.toml b/Cargo.toml
index 6c1442619b2f605fa3ae69d96cebae4270be0c04..102ae23c0893baf883273848fda6a103c6609611 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -35,11 +35,9 @@ reqwest = { version = "0.10.8", features = ["json"] }
 lazy_static = "1.4.0"
 num_enum = "0.5.1"
 chrono = "0.4.15"
-bcrypt = "0.8.2"
 time = "0.2.16"
 rand = "0.7.3"
-lru = "0.6.0"
-ws = "0.9.1"
+regex = "1"
 
 lettre = "0.10.0-alpha.1"
 env_logger = "0.7.1"
diff --git a/src/database/entities/user.rs b/src/database/entities/user.rs
index b55a8f88739e6cad9fbdf581cf9d594fc866b736..c6aca1f89ee2e7e6a62758cbd9a0a30adc75ab2c 100644
--- a/src/database/entities/user.rs
+++ b/src/database/entities/user.rs
@@ -2,14 +2,26 @@ use mongodb::bson::{doc, from_bson, Bson};
 use rauth::auth::Session;
 use rocket::http::Status;
 use serde::{Deserialize, Serialize};
+use crate::database::guards::reference::Ref;
 use crate::database::get_collection;
 use rocket::request::{self, FromRequest, Outcome, Request};
 
+#[derive(Serialize, Deserialize, Debug, Clone)]
+pub enum RelationshipStatus {
+    None,
+    User,
+    Friend,
+    Outgoing,
+    Incoming,
+    Blocked,
+    BlockedOther
+}
+
 #[derive(Serialize, Deserialize, Debug)]
 pub struct Relationship {
     #[serde(rename = "_id")]
     pub id: String,
-    pub status: u8,
+    pub status: RelationshipStatus,
 }
 
 #[derive(Serialize, Deserialize, Debug)]
@@ -47,3 +59,9 @@ impl<'a, 'r> FromRequest<'a, 'r> for User {
         }
     }
 }
+
+impl User {
+    pub fn as_ref(&self) -> Ref {
+        Ref { id: self.id.to_string() }
+    }
+}
diff --git a/src/database/guards/reference.rs b/src/database/guards/reference.rs
index a4282a1287878f52848f3135ecb1749c916538f7..851bb2fddd3f942f020abbbf2c50a5e23fd10b3f 100644
--- a/src/database/guards/reference.rs
+++ b/src/database/guards/reference.rs
@@ -18,11 +18,11 @@ impl Ref {
         Ok(Ref { id })
     }
 
-    pub async fn fetch_user(self) -> Result<User> {
+    pub async fn fetch_user(&self) -> Result<User> {
         let doc = get_collection("users")
             .find_one(
                 doc! {
-                    "_id": self.id
+                    "_id": &self.id
                 },
                 None
             )
diff --git a/src/database/permissions/mod.rs b/src/database/permissions/mod.rs
index 899aea7b62f1b31b9f97c81da4555e44bc9b1528..f2346a57ac12a4f383b0e2952c84d2e136400896 100644
--- a/src/database/permissions/mod.rs
+++ b/src/database/permissions/mod.rs
@@ -30,3 +30,22 @@ pub async fn temp_calc_perm(_user: &User, _target: &User) -> UserPermissions<[u3
 
     UserPermissions([UserPermission::Access + UserPermission::SendMessage + UserPermission::Invite])
 }
+
+use crate::database::entities::RelationshipStatus;
+use crate::database::guards::reference::Ref;
+
+pub fn get_relationship(a: &User, b: &Ref) -> RelationshipStatus {
+    if a.id == b.id {
+        return RelationshipStatus::Friend;
+    }
+
+    if let Some(relations) = &a.relations {
+        if let Some(relationship) = relations
+            .iter()
+            .find(|x| x.id == b.id) {
+            return relationship.status.clone();
+        }
+    }
+
+    RelationshipStatus::None
+}
diff --git a/src/routes/onboard/complete.rs b/src/routes/onboard/complete.rs
index 93a2daf08d15163cc309e24f606b8663b5d0c5bb..1ff0de089efb0bcfe2533967e905f3615d9434e6 100644
--- a/src/routes/onboard/complete.rs
+++ b/src/routes/onboard/complete.rs
@@ -7,10 +7,15 @@ use rocket_contrib::json::Json;
 use rauth::auth::Session;
 use validator::Validate;
 use mongodb::bson::doc;
+use regex::Regex;
+
+lazy_static! {
+    static ref RE_USERNAME: Regex = Regex::new(r"^[a-zA-Z0-9-_]+$").unwrap();
+}
 
 #[derive(Validate, Serialize, Deserialize)]
 pub struct Data {
-    #[validate(length(min = 2, max = 32))]
+    #[validate(length(min = 2, max = 32), regex = "RE_USERNAME")]
     username: String
 }
 
diff --git a/src/routes/users/add_friend.rs b/src/routes/users/add_friend.rs
new file mode 100644
index 0000000000000000000000000000000000000000..d0e1a6a478ffc1852f103f0fe72a8b4fd6e0f4c9
--- /dev/null
+++ b/src/routes/users/add_friend.rs
@@ -0,0 +1,84 @@
+use crate::{database::{entities::{User, RelationshipStatus}, get_collection, guards::reference::Ref, permissions::get_relationship}, util::result::Error};
+use rocket_contrib::json::JsonValue;
+use crate::util::result::Result;
+use mongodb::bson::doc;
+use futures::try_join;
+
+#[put("/<target>/friend")]
+pub async fn req(user: User, target: Ref) -> Result<JsonValue> {
+    let col = get_collection("users");
+
+    match get_relationship(&user, &target) {
+        RelationshipStatus::User => return Err(Error::NoEffect),
+        RelationshipStatus::Friend => return Err(Error::AlreadyFriends),
+        RelationshipStatus::Outgoing => return Err(Error::AlreadySentRequest),
+        RelationshipStatus::Blocked => return Err(Error::Blocked),
+        RelationshipStatus::BlockedOther => return Err(Error::BlockedByOther),
+        RelationshipStatus::Incoming => {
+            match try_join!(
+                col.update_one(
+                    doc! {
+                        "_id": &user.id,
+                        "relations._id": &target.id
+                    },
+                    doc! {
+                        "$set": {
+                            "relations.$.status": "Friend"
+                        }
+                    },
+                    None
+                ),
+                col.update_one(
+                    doc! {
+                        "_id": &target.id,
+                        "relations._id": &user.id
+                    },
+                    doc! {
+                        "$set": {
+                            "relations.$.status": "Friend"
+                        }
+                    },
+                    None
+                )
+            ) {
+                Ok(_) => Ok(json!({ "status": "Friend" })),
+                Err(_) => Err(Error::DatabaseError { operation: "update_one", with: "user" })
+            }
+        }
+        RelationshipStatus::None => {
+            match try_join!(
+                col.update_one(
+                    doc! {
+                        "_id": &user.id
+                    },
+                    doc! {
+                        "$push": {
+                            "relations": {
+                                "_id": &target.id,
+                                "status": "Outgoing"
+                            }
+                        }
+                    },
+                    None
+                ),
+                col.update_one(
+                    doc! {
+                        "_id": &target.id
+                    },
+                    doc! {
+                        "$push": {
+                            "relations": {
+                                "_id": &user.id,
+                                "status": "Incoming"
+                            }
+                        }
+                    },
+                    None
+                )
+            ) {
+                Ok(_) => Ok(json!({ "status": "Outgoing" })),
+                Err(_) => Err(Error::DatabaseError { operation: "update_one", with: "user" })
+            }
+        }
+    }
+}
diff --git a/src/routes/users/block_user.rs b/src/routes/users/block_user.rs
new file mode 100644
index 0000000000000000000000000000000000000000..59ccd4ea2fe485c286320e49f3c6946fa74789b8
--- /dev/null
+++ b/src/routes/users/block_user.rs
@@ -0,0 +1,101 @@
+use crate::{database::entities::RelationshipStatus, database::guards::reference::Ref, database::entities::User, database::permissions::get_relationship, util::result::Error, database::get_collection};
+use rocket_contrib::json::JsonValue;
+use crate::util::result::Result;
+use mongodb::bson::doc;
+use futures::try_join;
+
+#[put("/<target>/block")]
+pub async fn req(user: User, target: Ref) -> Result<JsonValue> {
+    let col = get_collection("users");
+
+    match get_relationship(&user, &target) {
+        RelationshipStatus::User |
+        RelationshipStatus::Blocked => Err(Error::NoEffect),
+        RelationshipStatus::BlockedOther => {
+            col.update_one(
+                doc! {
+                    "_id": &user.id,
+                    "relations._id": &target.id
+                },
+                doc! {
+                    "$set": {
+                        "relations.$.status": "Blocked"
+                    }
+                },
+                None
+            )
+            .await
+            .map_err(|_| Error::DatabaseError { operation: "update_one", with: "user" })?;
+
+            Ok(json!({ "status": "Blocked" }))
+        },
+        RelationshipStatus::None => {
+            match try_join!(
+                col.update_one(
+                    doc! {
+                        "_id": &user.id
+                    },
+                    doc! {
+                        "$push": {
+                            "relations": {
+                                "_id": &target.id,
+                                "status": "Blocked"
+                            }
+                        }
+                    },
+                    None
+                ),
+                col.update_one(
+                    doc! {
+                        "_id": &target.id
+                    },
+                    doc! {
+                        "$push": {
+                            "relations": {
+                                "_id": &user.id,
+                                "status": "BlockedOther"
+                            }
+                        }
+                    },
+                    None
+                )
+            ) {
+                Ok(_) => Ok(json!({ "status": "Blocked" })),
+                Err(_) => Err(Error::DatabaseError { operation: "update_one", with: "user" })
+            }
+        },
+        RelationshipStatus::Friend |
+        RelationshipStatus::Incoming |
+        RelationshipStatus::Outgoing => {
+            match try_join!(
+                col.update_one(
+                    doc! {
+                        "_id": &user.id,
+                        "relations._id": &target.id
+                    },
+                    doc! {
+                        "$set": {
+                            "relations.$.status": "Blocked"
+                        }
+                    },
+                    None
+                ),
+                col.update_one(
+                    doc! {
+                        "_id": &target.id,
+                        "relations._id": &user.id
+                    },
+                    doc! {
+                        "$set": {
+                            "relations.$.status": "BlockedOther"
+                        }
+                    },
+                    None
+                )
+            ) {
+                Ok(_) => Ok(json!({ "status": "Blocked" })),
+                Err(_) => Err(Error::DatabaseError { operation: "update_one", with: "user" })
+            }
+        }
+    }
+}
diff --git a/src/routes/users/fetch_relationship.rs b/src/routes/users/fetch_relationship.rs
new file mode 100644
index 0000000000000000000000000000000000000000..3c2c686937c7a769c6c7a2a9bd10015fd649035e
--- /dev/null
+++ b/src/routes/users/fetch_relationship.rs
@@ -0,0 +1,10 @@
+use crate::database::{entities::User, guards::reference::Ref, permissions::get_relationship};
+use rocket_contrib::json::JsonValue;
+use crate::util::result::Result;
+
+#[get("/<target>/relationship")]
+pub async fn req(user: User, target: Ref) -> Result<JsonValue> {
+    Ok(json!({
+        "status": get_relationship(&user, &target)
+    }))
+}
diff --git a/src/routes/users/fetch_relationships.rs b/src/routes/users/fetch_relationships.rs
new file mode 100644
index 0000000000000000000000000000000000000000..c9742444ff2808b4f4e3064ef4dc9c5e54ec30cf
--- /dev/null
+++ b/src/routes/users/fetch_relationships.rs
@@ -0,0 +1,14 @@
+use crate::database::entities::User;
+use rocket_contrib::json::JsonValue;
+use crate::util::result::Result;
+
+#[get("/relationships")]
+pub async fn req(user: User) -> Result<JsonValue> {
+    Ok(
+        if let Some(vec) = user.relations {
+            json!(vec)
+        } else {
+            json!([])
+        }
+    )
+}
diff --git a/src/routes/users/mod.rs b/src/routes/users/mod.rs
index fd5b017e53a9ce1de27011dfaeb35beb0eb8df2f..4a3e0047c6e8fde0dd79712a920cf30e90ea8d5b 100644
--- a/src/routes/users/mod.rs
+++ b/src/routes/users/mod.rs
@@ -3,11 +3,28 @@ use rocket::Route;
 mod fetch_user;
 mod fetch_dms;
 mod open_dm;
+mod fetch_relationships;
+mod fetch_relationship;
+mod add_friend;
+mod remove_friend;
+mod block_user;
+mod unblock_user;
 
 pub fn routes() -> Vec<Route> {
     routes! [
+        // User Information
         fetch_user::req,
+
+        // Direct Messaging
         fetch_dms::req,
         open_dm::req,
+
+        // Relationships
+        fetch_relationships::req,
+        fetch_relationship::req,
+        add_friend::req,
+        remove_friend::req,
+        block_user::req,
+        unblock_user::req,
     ]
 }
diff --git a/src/routes/users/remove_friend.rs b/src/routes/users/remove_friend.rs
new file mode 100644
index 0000000000000000000000000000000000000000..97290ce48f81c9b6b538312eeb8716bd4d25aace
--- /dev/null
+++ b/src/routes/users/remove_friend.rs
@@ -0,0 +1,52 @@
+use crate::{database::entities::RelationshipStatus, database::guards::reference::Ref, database::entities::User, database::permissions::get_relationship, util::result::Error, database::get_collection};
+use rocket_contrib::json::JsonValue;
+use crate::util::result::Result;
+use mongodb::bson::doc;
+use futures::try_join;
+
+#[delete("/<target>/friend")]
+pub async fn req(user: User, target: Ref) -> Result<JsonValue> {
+    let col = get_collection("users");
+
+    match get_relationship(&user, &target) {
+        RelationshipStatus::Blocked |
+        RelationshipStatus::BlockedOther |
+        RelationshipStatus::User |
+        RelationshipStatus::None => Err(Error::NoEffect),
+        RelationshipStatus::Friend |
+        RelationshipStatus::Outgoing |
+        RelationshipStatus::Incoming => {
+            match try_join!(
+                col.update_one(
+                    doc! {
+                        "_id": &user.id
+                    },
+                    doc! {
+                        "$pull": {
+                            "relations": {
+                                "_id": &target.id
+                            }
+                        }
+                    },
+                    None
+                ),
+                col.update_one(
+                    doc! {
+                        "_id": &target.id
+                    },
+                    doc! {
+                        "$pull": {
+                            "relations": {
+                                "_id": &user.id
+                            }
+                        }
+                    },
+                    None
+                )
+            ) {
+                Ok(_) => Ok(json!({ "status": "None" })),
+                Err(_) => Err(Error::DatabaseError { operation: "update_one", with: "user" })
+            }
+        }
+    }
+}
diff --git a/src/routes/users/unblock_user.rs b/src/routes/users/unblock_user.rs
new file mode 100644
index 0000000000000000000000000000000000000000..10e13b6e6125f60528343410b6a59e7f6d69e6b3
--- /dev/null
+++ b/src/routes/users/unblock_user.rs
@@ -0,0 +1,75 @@
+use crate::{database::entities::RelationshipStatus, database::guards::reference::Ref, database::entities::User, database::permissions::get_relationship, util::result::Error, database::get_collection};
+use rocket_contrib::json::JsonValue;
+use crate::util::result::Result;
+use mongodb::bson::doc;
+use futures::try_join;
+
+#[delete("/<target>/block")]
+pub async fn req(user: User, target: Ref) -> Result<JsonValue> {
+    let col = get_collection("users");
+
+    match get_relationship(&user, &target) {
+        RelationshipStatus::None |
+        RelationshipStatus::User |
+        RelationshipStatus::BlockedOther |
+        RelationshipStatus::Incoming |
+        RelationshipStatus::Outgoing |
+        RelationshipStatus::Friend => Err(Error::NoEffect),
+        RelationshipStatus::Blocked => {
+            match get_relationship(&target.fetch_user().await?, &user.as_ref()) {
+                RelationshipStatus::Blocked => {
+                    col.update_one(
+                        doc! {
+                            "_id": &user.id,
+                            "relations._id": &target.id
+                        },
+                        doc! {
+                            "$set": {
+                                "relations.$.status": "BlockedOther"
+                            }
+                        },
+                        None
+                    )
+                    .await
+                    .map_err(|_| Error::DatabaseError { operation: "update_one", with: "user" })?;
+        
+                    Ok(json!({ "status": "BlockedOther" }))
+                },
+                RelationshipStatus::BlockedOther => {
+                    match try_join!(
+                        col.update_one(
+                            doc! {
+                                "_id": &user.id
+                            },
+                            doc! {
+                                "$pull": {
+                                    "relations": {
+                                        "_id": &target.id
+                                    }
+                                }
+                            },
+                            None
+                        ),
+                        col.update_one(
+                            doc! {
+                                "_id": &target.id
+                            },
+                            doc! {
+                                "$pull": {
+                                    "relations": {
+                                        "_id": &user.id
+                                    }
+                                }
+                            },
+                            None
+                        )
+                    ) {
+                        Ok(_) => Ok(json!({ "status": "None" })),
+                        Err(_) => Err(Error::DatabaseError { operation: "update_one", with: "user" })
+                    }
+                },
+                _ => Err(Error::InternalError)
+            }
+        }
+    }
+}
diff --git a/src/util/result.rs b/src/util/result.rs
index 173ad27f6bfaa647bc7994386dac7a611d2b8b3e..7f980816829e7579152fd67e8c8f08b8e609aeaa 100644
--- a/src/util/result.rs
+++ b/src/util/result.rs
@@ -11,60 +11,35 @@ use json;
 #[serde(tag = "type")]
 pub enum Error {
     #[snafu(display("This error has not been labelled."))]
-    #[serde(rename = "unlabelled_error")]
     LabelMe,
 
     // ? Onboarding related errors.
     #[snafu(display("Already finished onboarding."))]
-    #[serde(rename = "already_onboarded")]
     AlreadyOnboarded,
     
     // ? User related errors.
     #[snafu(display("Username has already been taken."))]
-    #[serde(rename = "username_taken")]
     UsernameTaken,
     #[snafu(display("This user does not exist!"))]
-    #[serde(rename = "unknown_user")]
     UnknownUser,
+    #[snafu(display("Already friends with this user."))]
+    AlreadyFriends,
+    #[snafu(display("Already sent a request to this user."))]
+    AlreadySentRequest,
+    #[snafu(display("You have blocked this user."))]
+    Blocked,
+    #[snafu(display("You have been blocked by this user."))]
+    BlockedByOther,
 
     // ? General errors.
     #[snafu(display("Failed to validate fields."))]
-    #[serde(rename = "failed_validation")]
     FailedValidation { error: ValidationErrors },
     #[snafu(display("Encountered a database error."))]
-    #[serde(rename = "database_error")]
     DatabaseError { operation: &'static str, with: &'static str },
-
-    /* #[snafu(display("Failed to validate fields."))]
-    #[serde(rename = "failed_validation")]
-    FailedValidation { error: ValidationErrors },
-    #[snafu(display("Encountered a database error."))]
-    #[serde(rename = "database_error")]
-    DatabaseError,
-    #[snafu(display("Encountered an internal error."))]
-    #[serde(rename = "internal_error")]
+    #[snafu(display("Internal server error."))]
     InternalError,
-    #[snafu(display("Operation did not succeed."))]
-    #[serde(rename = "operation_failed")]
-    OperationFailed,
-    #[snafu(display("Missing authentication headers."))]
-    #[serde(rename = "missing_headers")]
-    MissingHeaders,
-    #[snafu(display("Invalid session information."))]
-    #[serde(rename = "invalid_session")]
-    InvalidSession,
-    #[snafu(display("User account has not been verified."))]
-    #[serde(rename = "unverified_account")]
-    UnverifiedAccount,
-    #[snafu(display("This user does not exist!"))]
-    #[serde(rename = "unknown_user")]
-    UnknownUser,
-    #[snafu(display("Email is use."))]
-    #[serde(rename = "email_in_use")]
-    EmailInUse,
-    #[snafu(display("Wrong password."))]
-    #[serde(rename = "wrong_password")]
-    WrongPassword, */
+    #[snafu(display("This request had no effect."))]
+    NoEffect,
 }
 
 pub type Result<T, E = Error> = std::result::Result<T, E>;
@@ -73,12 +48,21 @@ pub type Result<T, E = Error> = std::result::Result<T, E>;
 impl<'r> Responder<'r, 'static> for Error {
     fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> {
         let status = match self {
-            Error::AlreadyOnboarded => Status::Forbidden,
-            Error::DatabaseError { .. } => Status::InternalServerError,
-            Error::FailedValidation { .. } => Status::UnprocessableEntity,
             Error::LabelMe => Status::InternalServerError,
+
+            Error::AlreadyOnboarded => Status::Forbidden,
+
             Error::UnknownUser => Status::NotFound,
             Error::UsernameTaken => Status::Conflict,
+            Error::AlreadyFriends => Status::Conflict,
+            Error::AlreadySentRequest => Status::Conflict,
+            Error::Blocked => Status::Conflict,
+            Error::BlockedByOther => Status::Forbidden,
+
+            Error::FailedValidation { .. } => Status::UnprocessableEntity,
+            Error::DatabaseError { .. } => Status::InternalServerError,
+            Error::InternalError => Status::InternalServerError,
+            Error::NoEffect => Status::Ok,
         };
 
         // Serialize the error data structure into JSON.