Bug: [REFACTOR] Move `Request` and `RequestBuilder` structs to common_utils crate



### Feature Description

Currently `Request` and `RequestBuilder` structs reside in router crate. Since these are common structs used while building requests for connectors, it's better to move these to `common_utils` crate. This also reduces dependency on router crate for such things

### Possible Implementation

Move above structs to `common_utils` crate

### Have you spent some time checking if this feature request has been raised before?

- [X] I checked and didn't find a similar issue

### Have you read the Contributing Guidelines?

- [X] I have read the [Contributing Guidelines](https://github.com/juspay/hyperswitch/blob/main/docs/CONTRIBUTING.md)

### Are you willing to submit a PR?

Yes, I am willing to submit a PR!
diff --git a/Cargo.lock b/Cargo.lock
index a30738c69da..082bb476dec 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -497,9 +497,9 @@ dependencies = [
 
 [[package]]
 name = "async-channel"
-version = "1.8.0"
+version = "1.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833"
+checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35"
 dependencies = [
  "concurrent-queue",
  "event-listener",
@@ -1464,6 +1464,7 @@ dependencies = [
  "fake",
  "futures",
  "hex",
+ "http",
  "masking",
  "md5",
  "nanoid",
@@ -1473,6 +1474,7 @@ dependencies = [
  "quick-xml",
  "rand 0.8.5",
  "regex",
+ "reqwest",
  "ring",
  "router_env",
  "serde",
@@ -1480,6 +1482,7 @@ dependencies = [
  "serde_urlencoded",
  "signal-hook",
  "signal-hook-tokio",
+ "strum 0.24.1",
  "test-case",
  "thiserror",
  "time 0.3.22",
@@ -2080,9 +2083,9 @@ dependencies = [
 
 [[package]]
 name = "fake"
-version = "2.6.1"
+version = "2.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a44c765350db469b774425ff1c833890b16ceb9612fb5d7c4bbdf4a1b55f876"
+checksum = "9af7b0c58ac9d03169e27f080616ce9f64004edca3d2ef4147a811c21b23b319"
 dependencies = [
  "rand 0.8.5",
  "unidecode",
diff --git a/crates/common_utils/Cargo.toml b/crates/common_utils/Cargo.toml
index 166f5973928..e21aecbb421 100644
--- a/crates/common_utils/Cargo.toml
+++ b/crates/common_utils/Cargo.toml
@@ -19,17 +19,20 @@ diesel = "2.1.0"
 error-stack = "0.3.1"
 futures = { version = "0.3.28", optional = true }
 hex = "0.4.3"
+http = "0.2.9"
 md5 = "0.7.0"
 nanoid = "0.4.0"
 once_cell = "1.18.0"
 quick-xml = { version = "0.28.2", features = ["serialize"] }
 rand = "0.8.5"
 regex = "1.8.4"
+reqwest = { version = "0.11.18", features = ["json", "native-tls", "gzip", "multipart"] }
 ring = { version = "0.16.20", features = ["std"] }
 serde = { version = "1.0.163", features = ["derive"] }
 serde_json = "1.0.96"
 serde_urlencoded = "0.7.1"
 signal-hook = { version = "0.3.15", optional = true }
+strum = { version = "0.24.1", features = ["derive"] }
 thiserror = "1.0.40"
 time = { version = "0.3.21", features = ["serde", "serde-well-known", "std"] }
 tokio = { version = "1.28.2", features = ["macros", "rt-multi-thread"], optional = true }
diff --git a/crates/common_utils/src/lib.rs b/crates/common_utils/src/lib.rs
index 0bdd84848f5..01c9c80fcec 100644
--- a/crates/common_utils/src/lib.rs
+++ b/crates/common_utils/src/lib.rs
@@ -9,6 +9,8 @@ pub mod errors;
 pub mod ext_traits;
 pub mod fp_utils;
 pub mod pii;
+#[allow(missing_docs)] // Todo: add docs
+pub mod request;
 #[cfg(feature = "signals")]
 pub mod signals;
 pub mod validation;
diff --git a/crates/common_utils/src/request.rs b/crates/common_utils/src/request.rs
new file mode 100644
index 00000000000..64bce8649d9
--- /dev/null
+++ b/crates/common_utils/src/request.rs
@@ -0,0 +1,206 @@
+use masking::{Maskable, Secret};
+#[cfg(feature = "logs")]
+use router_env::logger;
+use serde::{Deserialize, Serialize};
+
+use crate::errors;
+
+pub type Headers = std::collections::HashSet<(String, Maskable<String>)>;
+
+#[derive(
+    Clone, Copy, Debug, Eq, PartialEq, Deserialize, Serialize, strum::Display, strum::EnumString,
+)]
+#[serde(rename_all = "UPPERCASE")]
+#[strum(serialize_all = "UPPERCASE")]
+pub enum Method {
+    Get,
+    Post,
+    Put,
+    Delete,
+}
+
+#[derive(Deserialize, Serialize, Debug)]
+pub enum ContentType {
+    Json,
+    FormUrlEncoded,
+    FormData,
+}
+
+fn default_request_headers() -> [(String, Maskable<String>); 1] {
+    use http::header;
+
+    [(header::VIA.to_string(), "HyperSwitch".to_string().into())]
+}
+
+#[derive(Debug)]
+pub struct Request {
+    pub url: String,
+    pub headers: Headers,
+    pub payload: Option<Secret<String>>,
+    pub method: Method,
+    pub content_type: Option<ContentType>,
+    pub certificate: Option<String>,
+    pub certificate_key: Option<String>,
+    pub form_data: Option<reqwest::multipart::Form>,
+}
+
+impl Request {
+    pub fn new(method: Method, url: &str) -> Self {
+        Self {
+            method,
+            url: String::from(url),
+            headers: std::collections::HashSet::new(),
+            payload: None,
+            content_type: None,
+            certificate: None,
+            certificate_key: None,
+            form_data: None,
+        }
+    }
+
+    pub fn set_body(&mut self, body: String) {
+        self.payload = Some(body.into());
+    }
+
+    pub fn add_default_headers(&mut self) {
+        self.headers.extend(default_request_headers());
+    }
+
+    pub fn add_header(&mut self, header: &str, value: Maskable<String>) {
+        self.headers.insert((String::from(header), value));
+    }
+
+    pub fn add_content_type(&mut self, content_type: ContentType) {
+        self.content_type = Some(content_type);
+    }
+
+    pub fn add_certificate(&mut self, certificate: Option<String>) {
+        self.certificate = certificate;
+    }
+
+    pub fn add_certificate_key(&mut self, certificate_key: Option<String>) {
+        self.certificate = certificate_key;
+    }
+
+    pub fn set_form_data(&mut self, form_data: reqwest::multipart::Form) {
+        self.form_data = Some(form_data);
+    }
+}
+
+#[derive(Debug)]
+pub struct RequestBuilder {
+    pub url: String,
+    pub headers: Headers,
+    pub payload: Option<Secret<String>>,
+    pub method: Method,
+    pub content_type: Option<ContentType>,
+    pub certificate: Option<String>,
+    pub certificate_key: Option<String>,
+    pub form_data: Option<reqwest::multipart::Form>,
+}
+
+impl RequestBuilder {
+    pub fn new() -> Self {
+        Self {
+            method: Method::Get,
+            url: String::with_capacity(1024),
+            headers: std::collections::HashSet::new(),
+            payload: None,
+            content_type: None,
+            certificate: None,
+            certificate_key: None,
+            form_data: None,
+        }
+    }
+
+    pub fn url(mut self, url: &str) -> Self {
+        self.url = url.into();
+        self
+    }
+
+    pub fn method(mut self, method: Method) -> Self {
+        self.method = method;
+        self
+    }
+
+    pub fn attach_default_headers(mut self) -> Self {
+        self.headers.extend(default_request_headers());
+        self
+    }
+
+    pub fn header(mut self, header: &str, value: &str) -> Self {
+        self.headers.insert((header.into(), value.into()));
+        self
+    }
+
+    pub fn headers(mut self, headers: Vec<(String, Maskable<String>)>) -> Self {
+        let mut h = headers.into_iter().map(|(h, v)| (h, v));
+        self.headers.extend(&mut h);
+        self
+    }
+
+    pub fn form_data(mut self, form_data: Option<reqwest::multipart::Form>) -> Self {
+        self.form_data = form_data;
+        self
+    }
+
+    pub fn body(mut self, option_body: Option<RequestBody>) -> Self {
+        self.payload = option_body.map(RequestBody::get_inner_value);
+        self
+    }
+
+    pub fn content_type(mut self, content_type: ContentType) -> Self {
+        self.content_type = Some(content_type);
+        self
+    }
+
+    pub fn add_certificate(mut self, certificate: Option<String>) -> Self {
+        self.certificate = certificate;
+        self
+    }
+
+    pub fn add_certificate_key(mut self, certificate_key: Option<String>) -> Self {
+        self.certificate_key = certificate_key;
+        self
+    }
+
+    pub fn build(self) -> Request {
+        Request {
+            method: self.method,
+            url: self.url,
+            headers: self.headers,
+            payload: self.payload,
+            content_type: self.content_type,
+            certificate: self.certificate,
+            certificate_key: self.certificate_key,
+            form_data: self.form_data,
+        }
+    }
+}
+
+impl Default for RequestBuilder {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+#[derive(Clone, Debug)]
+pub struct RequestBody(Secret<String>);
+
+impl RequestBody {
+    pub fn log_and_get_request_body<T, F>(
+        body: T,
+        encoder: F,
+    ) -> errors::CustomResult<Self, errors::ParsingError>
+    where
+        F: FnOnce(T) -> errors::CustomResult<String, errors::ParsingError>,
+        T: std::fmt::Debug,
+    {
+        #[cfg(feature = "logs")]
+        logger::info!(connector_request_body=?body);
+        Ok(Self(Secret::new(encoder(body)?)))
+    }
+    pub fn get_inner_value(request_body: Self) -> Secret<String> {
+        request_body.0
+    }
+}
diff --git a/crates/router/src/services/api.rs b/crates/router/src/services/api.rs
index 8b9b0b6afeb..99400050df3 100644
--- a/crates/router/src/services/api.rs
+++ b/crates/router/src/services/api.rs
@@ -14,14 +14,14 @@ use actix_web::{body, HttpRequest, HttpResponse, Responder, ResponseError};
 use api_models::enums::CaptureMethod;
 pub use client::{proxy_bypass_urls, ApiClient, MockApiClient, ProxyClient};
 use common_utils::errors::ReportSwitchExt;
+pub use common_utils::request::{ContentType, Method, Request, RequestBuilder};
 use error_stack::{report, IntoReport, Report, ResultExt};
 use masking::{ExposeOptionInterface, PeekInterface};
 use router_env::{instrument, tracing, Tag};
 use serde::Serialize;
 use serde_json::json;
 
-use self::request::{ContentType, HeaderExt, RequestBuilderExt};
-pub use self::request::{Method, Request, RequestBuilder};
+use self::request::{HeaderExt, RequestBuilderExt};
 use crate::{
     configs::settings::{Connectors, Settings},
     consts,
@@ -1229,9 +1229,9 @@ pub fn build_redirection_form(
                                                     f.method='POST';
                                                     i.name = 'authentication_response';
                                                     i.value = JSON.stringify(payload);
-                                                    f.appendChild(i); 
+                                                    f.appendChild(i);
                                                     f.body = JSON.stringify(payload);
-                                                    document.body.appendChild(f); 
+                                                    document.body.appendChild(f);
                                                     f.submit();
                                                     }}
                                                 }});
diff --git a/crates/router/src/services/api/request.rs b/crates/router/src/services/api/request.rs
index 21b4a5acdcb..1f672b0f0de 100644
--- a/crates/router/src/services/api/request.rs
+++ b/crates/router/src/services/api/request.rs
@@ -1,193 +1,12 @@
-use std::{collections, str::FromStr};
+use std::str::FromStr;
 
+pub use common_utils::request::ContentType;
+use common_utils::request::Headers;
 use error_stack::{IntoReport, ResultExt};
-use masking::Secret;
 pub use masking::{Mask, Maskable};
 use router_env::{instrument, tracing};
-use serde::{Deserialize, Serialize};
 
-use crate::{
-    core::errors::{self, CustomResult},
-    types,
-};
-
-pub(crate) type Headers = collections::HashSet<(String, Maskable<String>)>;
-
-#[derive(
-    Clone, Copy, Debug, Eq, PartialEq, Deserialize, Serialize, strum::Display, strum::EnumString,
-)]
-#[serde(rename_all = "UPPERCASE")]
-#[strum(serialize_all = "UPPERCASE")]
-pub enum Method {
-    Get,
-    Post,
-    Put,
-    Delete,
-}
-
-#[derive(Deserialize, Serialize, Debug)]
-pub enum ContentType {
-    Json,
-    FormUrlEncoded,
-    FormData,
-}
-
-fn default_request_headers() -> [(String, Maskable<String>); 1] {
-    use http::header;
-
-    [(header::VIA.to_string(), "HyperSwitch".to_string().into())]
-}
-
-#[derive(Debug)]
-pub struct Request {
-    pub url: String,
-    pub headers: Headers,
-    pub payload: Option<Secret<String>>,
-    pub method: Method,
-    pub content_type: Option<ContentType>,
-    pub certificate: Option<String>,
-    pub certificate_key: Option<String>,
-    pub form_data: Option<reqwest::multipart::Form>,
-}
-
-impl Request {
-    pub fn new(method: Method, url: &str) -> Self {
-        Self {
-            method,
-            url: String::from(url),
-            headers: collections::HashSet::new(),
-            payload: None,
-            content_type: None,
-            certificate: None,
-            certificate_key: None,
-            form_data: None,
-        }
-    }
-
-    pub fn set_body(&mut self, body: String) {
-        self.payload = Some(body.into());
-    }
-
-    pub fn add_default_headers(&mut self) {
-        self.headers.extend(default_request_headers());
-    }
-
-    pub fn add_header(&mut self, header: &str, value: Maskable<String>) {
-        self.headers.insert((String::from(header), value));
-    }
-
-    pub fn add_content_type(&mut self, content_type: ContentType) {
-        self.content_type = Some(content_type);
-    }
-
-    pub fn add_certificate(&mut self, certificate: Option<String>) {
-        self.certificate = certificate;
-    }
-
-    pub fn add_certificate_key(&mut self, certificate_key: Option<String>) {
-        self.certificate = certificate_key;
-    }
-
-    pub fn set_form_data(&mut self, form_data: reqwest::multipart::Form) {
-        self.form_data = Some(form_data);
-    }
-}
-
-pub struct RequestBuilder {
-    pub url: String,
-    pub headers: Headers,
-    pub payload: Option<Secret<String>>,
-    pub method: Method,
-    pub content_type: Option<ContentType>,
-    pub certificate: Option<String>,
-    pub certificate_key: Option<String>,
-    pub form_data: Option<reqwest::multipart::Form>,
-}
-
-impl RequestBuilder {
-    pub fn new() -> Self {
-        Self {
-            method: Method::Get,
-            url: String::with_capacity(1024),
-            headers: std::collections::HashSet::new(),
-            payload: None,
-            content_type: None,
-            certificate: None,
-            certificate_key: None,
-            form_data: None,
-        }
-    }
-
-    pub fn url(mut self, url: &str) -> Self {
-        self.url = url.into();
-        self
-    }
-
-    pub fn method(mut self, method: Method) -> Self {
-        self.method = method;
-        self
-    }
-
-    pub fn attach_default_headers(mut self) -> Self {
-        self.headers.extend(default_request_headers());
-        self
-    }
-
-    pub fn header(mut self, header: &str, value: &str) -> Self {
-        self.headers.insert((header.into(), value.into()));
-        self
-    }
-
-    pub fn headers(mut self, headers: Vec<(String, Maskable<String>)>) -> Self {
-        let mut h = headers.into_iter().map(|(h, v)| (h, v));
-        self.headers.extend(&mut h);
-        self
-    }
-
-    pub fn form_data(mut self, form_data: Option<reqwest::multipart::Form>) -> Self {
-        self.form_data = form_data;
-        self
-    }
-
-    pub fn body(mut self, option_body: Option<types::RequestBody>) -> Self {
-        self.payload = option_body.map(types::RequestBody::get_inner_value);
-        self
-    }
-
-    pub fn content_type(mut self, content_type: ContentType) -> Self {
-        self.content_type = Some(content_type);
-        self
-    }
-
-    pub fn add_certificate(mut self, certificate: Option<String>) -> Self {
-        self.certificate = certificate;
-        self
-    }
-
-    pub fn add_certificate_key(mut self, certificate_key: Option<String>) -> Self {
-        self.certificate_key = certificate_key;
-        self
-    }
-
-    pub fn build(self) -> Request {
-        Request {
-            method: self.method,
-            url: self.url,
-            headers: self.headers,
-            payload: self.payload,
-            content_type: self.content_type,
-            certificate: self.certificate,
-            certificate_key: self.certificate_key,
-            form_data: self.form_data,
-        }
-    }
-}
-
-impl Default for RequestBuilder {
-    fn default() -> Self {
-        Self::new()
-    }
-}
+use crate::core::errors::{self, CustomResult};
 
 pub(super) trait HeaderExt {
     fn construct_header_map(
diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs
index 4c1c3d8c3a5..b1488d6df35 100644
--- a/crates/router/src/types.rs
+++ b/crates/router/src/types.rs
@@ -17,6 +17,7 @@ pub use api_models::{
     enums::{Connector, PayoutConnectors},
     payouts as payout_types,
 };
+pub use common_utils::request::RequestBody;
 use common_utils::{pii, pii::Email};
 use data_models::mandates::MandateData;
 use error_stack::{IntoReport, ResultExt};
@@ -1062,26 +1063,6 @@ impl<F1, F2, T1, T2> From<(&RouterData<F1, T1, PaymentsResponseData>, T2)>
     }
 }
 
-#[derive(Clone, Debug)]
-pub struct RequestBody(Secret<String>);
-
-impl RequestBody {
-    pub fn log_and_get_request_body<T, F>(
-        body: T,
-        encoder: F,
-    ) -> errors::CustomResult<Self, errors::ParsingError>
-    where
-        F: FnOnce(T) -> errors::CustomResult<String, errors::ParsingError>,
-        T: std::fmt::Debug,
-    {
-        router_env::logger::info!(connector_request_body=?body);
-        Ok(Self(Secret::new(encoder(body)?)))
-    }
-    pub fn get_inner_value(request_body: Self) -> Secret<String> {
-        request_body.0
-    }
-}
-
 #[cfg(feature = "payouts")]
 impl<F1, F2>
     From<(

## Type of Change
<!-- Put an `x` in the boxes that apply -->

- [ ] Bugfix
- [ ] New feature
- [ ] Enhancement
- [x] Refactoring
- [ ] Dependency updates
- [ ] Documentation
- [ ] CI/CD

## Description
<!-- Describe your changes in detail -->
Currently `Request` and `RequestBuilder` structs reside in router crate. Since these are common structs used while building requests for connectors, it's better to move these to common_utils crate. This also reduces dependency on router crate for such things

### Additional Changes

- [ ] This PR modifies the API contract
- [ ] This PR modifies the database schema
- [ ] This PR modifies application configuration/environment variables

<!--
Provide links to the files with corresponding changes.

Following are the paths where you can find config files:
1. `config`
2. `crates/router/src/configs`
3. `loadtest/config`
-->


## Motivation and Context
<!--
Why is this change required? What problem does it solve?
If it fixes an open issue, please link to the issue here.

If you don't have an issue, we'd recommend starting with one first so the PR
can focus on the implementation (unless it is an obvious bug or documentation fix
that will have little conversation).
-->


## How did you test it?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->


## Checklist
<!-- Put an `x` in the boxes that apply -->

- [x] I formatted the code `cargo +nightly fmt --all`
- [x] I addressed lints thrown by `cargo clippy`
- [x] I reviewed the submitted code
- [ ] I added unit tests for my changes where possible
- [ ] I added a [CHANGELOG](/CHANGELOG.md) entry if applicable
