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 e33dbc7 commit 4ce9181
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 2 deletions.
9 changes: 9 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,12 @@
resolver = "2" # Specify the resolver version that matches edition 2021

members = ["crates/gateway"]

[workspace.package]
version = "0.1.0"
edition = "2021"

[workspace.dependencies]
hyper = "0.13.9"
tokio = { version = "0.2", features = ["full"] }
thiserror = "1.0"
12 changes: 10 additions & 2 deletions crates/gateway/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
[package]
name = "gateway"
version = "0.1.0"
edition = "2021"
version.workspace = true
edition.workspace = true

[dependencies]
hyper.workspace = true
tokio.workspace = true
thiserror.workspace = true

[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,
}
60 changes: 60 additions & 0 deletions crates/gateway/src/gateway.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
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;
use std::str::FromStr;

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

const NOT_FOUND_RESPONSE: &str = "Not found.";
pub type GatewayResult = Result<(), GatewayError>;

pub struct Gateway {
pub gateway_config: GatewayConfig,
}

impl Gateway {
pub async fn build_server(&self) -> GatewayResult {
let addr = SocketAddr::from_str(&self.gateway_config.bind_address)
.map_err(|_| GatewayError::ServerError)?;

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

Server::bind(&addr)
.serve(make_service)
.await
.map_err(|_| GatewayError::ServerError)?;

Ok(())
}
}

pub struct GatewayConfig {
pub bind_address: String,
}

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> {
if true {
return Response::builder()
.status(200)
.body(Body::from("Server is alive"))
.map_err(|_| GatewayError::InternalServerError);
}
unimplemented!("Future error handling might be implemented here.");
}
44 changes: 44 additions & 0 deletions crates/gateway/src/gateway_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use crate::gateway::handle_request;
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 = 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 {
gateway_config: GatewayConfig {
bind_address: "0.0.0.0:8080".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 4ce9181

Please sign in to comment.