Skip to content

Commit

Permalink
Implement API Gateway skeleton and unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ayeletstarkware committed Mar 19, 2024
1 parent 77bbc06 commit 8941ef1
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 0 deletions.
8 changes: 8 additions & 0 deletions crates/gateway/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,11 @@
name = "gateway"
version = "0.1.0"
edition = "2021"

[dependencies]
hyper = "0.13.9"
tokio = { version = "0.2", features = ["full"] }
thiserror = "1.0"

[lib]
name = "gateway_lib"
9 changes: 9 additions & 0 deletions crates/gateway/src/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use thiserror::Error;

#[derive(Debug, Error)]
pub enum GatewayError {
#[error("Internal server error")]
InternalServerError,
#[error("Error while starting the server")]
ServerError,
}
57 changes: 57 additions & 0 deletions crates/gateway/src/gateway.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use crate::errors::GatewayError;
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Method, Request, Response, Server};
use std::convert::Infallible;
use std::net::SocketAddr;

#[cfg(test)]
#[path = "gateway_test.rs"]
pub mod gateway_test;

const NOT_FOUND_RESPONSE: &str = "Not found.";

pub struct GatewayConfig {
pub config: String,
}

pub struct Gateway {
pub gateway_config: GatewayConfig,
}

impl Gateway {
pub fn new(gateway_config: GatewayConfig) -> Self {
Self { gateway_config }
}

pub async fn build_server(&self) -> Result<(), GatewayError> {
let addr = SocketAddr::from(([127, 0, 0, 1], 8080));

let make_service = make_service_fn(|_conn| async {
Ok::<_, Infallible>(service_fn(Self::handle_request))
});

match Server::bind(&addr).serve(make_service).await {
Ok(_) => Ok(()),
Err(_) => Err(GatewayError::ServerError),
}
}

async fn handle_request(request: Request<Body>) -> Result<Response<Body>, GatewayError> {
let (parts, _body) = request.into_parts();
let response = match (parts.method, parts.uri.path()) {
(Method::GET, "/is_alive") => is_alive(),
_ => Ok(Response::builder()
.status(404)
.body(Body::from(NOT_FOUND_RESPONSE))
.map_err(|_| GatewayError::InternalServerError)?),
};
response
}
}

fn is_alive() -> Result<Response<Body>, GatewayError> {
Response::builder()
.status(200)
.body(Body::from("Server is alive"))
.map_err(|_| GatewayError::InternalServerError)
}
41 changes: 41 additions & 0 deletions crates/gateway/src/gateway_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use crate::gateway::Gateway;
use crate::gateway::GatewayConfig;
use hyper::{Body, Request};
use tokio::time::{delay_for, Duration};

#[tokio::test]
async fn test_invalid_request() {
// Create a sample GET request for an invalid path
let request = Request::get("/some_invalid_path")
.body(Body::empty())
.unwrap();
let response = Gateway::handle_request(request).await.unwrap();

assert_eq!(response.status(), 404);
assert_eq!(
String::from_utf8_lossy(&hyper::body::to_bytes(response.into_body()).await.unwrap()),
"Not found."
);
}

#[tokio::test]
async fn test_build_server() {
let gateway = Gateway::new(GatewayConfig {
config: "some_configurations".to_string(),
});

tokio::spawn(async move {
gateway.build_server().await.unwrap();
});
delay_for(Duration::from_secs(1)).await;

let client = hyper::Client::new();
let uri = "http://127.0.0.1:8080/is_alive".parse().unwrap();
let response = client.get(uri).await.unwrap();

assert_eq!(response.status(), 200);
assert_eq!(
String::from_utf8_lossy(&hyper::body::to_bytes(response.into_body()).await.unwrap()),
"Server is alive"
);
}
2 changes: 2 additions & 0 deletions crates/gateway/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod errors;
pub mod gateway;

0 comments on commit 8941ef1

Please sign in to comment.