Skip to content

Commit

Permalink
feat/response-lib
Browse files Browse the repository at this point in the history
  • Loading branch information
MadebyAe committed Apr 13, 2024
1 parent 332796d commit 2a91c03
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 13 deletions.
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ edition = "2021"
repository = "https://github.com/MadebyAe/lambda-utils"
description = "Lambda Utils for AWS Rust Lambda"
authors = ["Ae <[email protected]>"]
keywords = ["aws", "lambda", "serverless", "rust"]
keywords = ["aws", "lambda", "serverless", "rust", "macros", "mongodb", "sqs"]
categories = ["utils"]
license = "MIT"

Expand All @@ -14,6 +14,7 @@ aws-config = { version = "1.1.2", features = ["behavior-version-latest"], option
aws-sdk-sqs = { version = "1.9.0", optional = true }
aws-types = { version = "1.1.2", optional = true }
aws_lambda_events = { version = "0.15.0", optional = true }
chrono = { version = "0.4", optional = true }
lambda_http = { version = "0.11.1", optional = true }
mongodb = { version = "2.3.1", optional = true }
once_cell = { version = "1.17.0", optional = true }
Expand All @@ -26,4 +27,5 @@ tokio = { version = "1.17.0", features = ["full", "test-util"] }
headers = ["lambda_http", "serde_json"]
mongodb = ["dep:mongodb", "once_cell"]
network = ["aws_lambda_events", "lambda_http"]
response = ["chrono", "lambda_http", "serde_json"]
sqs = ["aws-sdk-sqs", "aws-config", "serde_json"]
29 changes: 19 additions & 10 deletions src/headers.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use lambda_http::Request;
use serde_json::to_string;
use serde_json::{json, Value};
use std::collections::HashMap;

pub fn get_header_value(request: &Request, value: String) -> String {
Expand All @@ -18,7 +18,7 @@ pub fn get_header_user_agent(request: &Request) -> String {
return get_header_value(request, "User-Agent".to_string());
}

pub fn get_header_cookies(request: &Request) -> String {
pub fn get_header_cookies(request: &Request) -> Value {
let mut cookies = HashMap::new();

if let Some(cookie_header) = request.headers().get("Cookie") {
Expand All @@ -40,22 +40,31 @@ pub fn get_header_cookies(request: &Request) -> String {
}
}

return to_string(&cookies).unwrap();
return json!(&cookies);
}

#[cfg(test)]
mod tests {
mod headers_tests {
use super::*;
use lambda_http::http::header::{HeaderMap, HeaderValue};
use lambda_http::http::header::{HeaderName, HeaderValue};
use lambda_http::{Body, Request};

fn mock_request(headers: Vec<(&str, &str)>) -> Request {
let mut header_map = HeaderMap::new();
let mut request = Request::new(Body::Empty); // Correct use of Request::new with Body::Empty for lambda_http

for (key, value) in headers {
header_map.insert(key, HeaderValue::from_static(value));
match key.parse::<HeaderName>() {
Ok(parsed_key) => match HeaderValue::from_str(value) {
Ok(header_value) => {
request.headers_mut().insert(parsed_key, header_value);
}
Err(e) => eprintln!("Failed to create HeaderValue: {}", e),
},
Err(e) => eprintln!("Failed to parse HeaderName: {}", e),
}
}

Request::new(Body::Empty).with_headers(header_map)
return request;
}

#[test]
Expand Down Expand Up @@ -84,10 +93,10 @@ mod tests {

#[test]
fn test_get_header_cookies() {
let request = mock_request(vec![("Cookie", "username=user; session=token")]);
let request = mock_request(vec![("Cookie", "username=username; session=session;")]);
assert_eq!(
get_header_cookies(&request),
r#"{"session":"token","username":"user"}"#
json!({ "session":"session","username":"username" })
);
}
}
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,8 @@ pub mod mongodb;
#[cfg(feature = "network")]
pub mod network;

#[cfg(feature = "response")]
pub mod response;

#[cfg(feature = "sqs")]
pub mod sqs;
5 changes: 4 additions & 1 deletion src/mongodb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ pub fn get_mongodb_client() -> Result<&'static Client, Box<dyn Error + Send + Sy
}

#[cfg(test)]
mod tests {
mod mongodb_tests {
use super::*;
use std::env;

#[tokio::test]
async fn test_create_mongodb_client() {
env::set_var(
Expand Down
86 changes: 86 additions & 0 deletions src/response.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#[macro_export]
macro_rules! json_error {
($status_code:expr, $message:expr) => {{
use chrono::Utc;
use lambda_http::Body;
use lambda_http::http::{Response, StatusCode};
use serde_json::json;

fn error_code_to_type(status: StatusCode) -> &'static str {
match status {
StatusCode::BAD_REQUEST => "BadRequest",
StatusCode::FORBIDDEN => "Forbidden",
StatusCode::INTERNAL_SERVER_ERROR => "InternalServerError",
StatusCode::UNAUTHORIZED => "Unauthorized",
_ => "Unknown",
}
}

let now = Utc::now();
let body = json!({
"code": $status_code.as_u16(),
"message": $message,
"timestamp": now.timestamp_millis(),
"type": error_code_to_type($status_code),
}).to_string();

Response::builder()
.status($status_code)
.header("Content-Type", "application/json")
.body(Body::from(body))
.expect("Failed to construct error response")
}};
}
pub use json_error;

#[macro_export]
macro_rules! json_ok {
($data:tt) => {{
use lambda_http::http::Response;
use lambda_http::Body;
use serde_json::json;

let body = json!($data).to_string();

Response::builder()
.status(StatusCode::OK)
.header("Content-Type", "application/json")
.body(Body::from(body))
.expect("Failed to construct success response")
}};
}
pub use json_ok;

#[cfg(test)]
mod response_tests {
use super::*;
use lambda_http::http::StatusCode;
use lambda_http::{Body, Response};
use serde_json::{from_slice, Value};

fn extract_body(response: Response<Body>) -> Value {
let body = response.into_body();

return from_slice(&body).unwrap_or_default();
}

#[test]
fn json_error_macro_test() {
let response = json_error!(StatusCode::FORBIDDEN, "Forbidden access");
assert_eq!(response.status(), StatusCode::FORBIDDEN);

let body = extract_body(response);
assert_eq!(body["code"], 403);
assert_eq!(body["message"], "Forbidden access");
assert_eq!(body["type"], "Forbidden");
}

#[test]
fn json_ok_macro_test() {
let response = json_ok!({ "data": "Success" });
assert_eq!(response.status(), StatusCode::OK);

let body = extract_body(response);
assert_eq!(body["data"], "Success");
}
}
3 changes: 2 additions & 1 deletion src/sqs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ pub async fn receive_from_sqs() -> Result<ReceiveMessageOutput, SqsError> {
}

#[cfg(test)]
mod tests {
mod sqs_tests {
use super::*;
use serde_json::{json, Value};

fn create_mock_object() -> Value {
Expand Down

0 comments on commit 2a91c03

Please sign in to comment.