diff --git a/mock-api/README.md b/mock-api/README.md index 6ddaf10..1075b13 100644 --- a/mock-api/README.md +++ b/mock-api/README.md @@ -1,5 +1,33 @@ +### Dependencies + +1. `rust` https://rust-lang.github.io/rustup/installation/index.html + + ### How to run In the root directory of the project -`cargo run -p mock-api` \ No newline at end of file +`cargo run -p mock-api` + + +### Routes + +* `GET http://127.0.0.1:3000/posts` + + Get all posts + +* `GET http://127.0.0.1:3000/posts/1` + + Get specific post + +* `GET http://127.0.0.1:3000/users` + + Get all users + +* `GET http://127.0.0.1:3000/users/1` + + Get specific user + +* `GET http://127.0.0.1:3000/users?id=1&id=2` + + Get specified users \ No newline at end of file diff --git a/mock-api/src/database.rs b/mock-api/src/database.rs index 58453fd..6d66a3c 100644 --- a/mock-api/src/database.rs +++ b/mock-api/src/database.rs @@ -5,6 +5,8 @@ use serde_json::json; use crate::{PostData, UserData}; +/// Helper struct that is used to store the data +/// for the responses pub struct Database { user_template: serde_json::Value, post_template: serde_json::Value, @@ -23,6 +25,7 @@ fn geo_add_fractional_part(val: &mut f64) { } impl Database { + /// Initialize the database with random data pub fn new() -> Self { Self { user_template: json!({ @@ -51,6 +54,7 @@ impl Database { } } + /// Used to reset the database and generate new data pub fn reset(&self) -> Result<(), anyhow::Error> { // clear the previous data from database. self.users @@ -91,18 +95,22 @@ impl Database { Ok(()) } + /// Used to get all posts pub fn posts(&self) -> Vec { self.posts.lock().unwrap().values().cloned().collect() } + /// Used to get a post pub fn post(&self, id: i64) -> Option { self.posts.lock().unwrap().get(&id).cloned() } + /// Used to get all users pub fn users(&self) -> Vec { self.users.lock().unwrap().values().cloned().collect() } + /// Used to get a user pub fn user(&self, id: i64) -> Option { self.users.lock().unwrap().get(&id).cloned() } diff --git a/mock-api/src/lib.rs b/mock-api/src/lib.rs index 213a3da..8bbb83a 100644 --- a/mock-api/src/lib.rs +++ b/mock-api/src/lib.rs @@ -6,6 +6,7 @@ pub mod database; pub mod routes; pub mod utils; +/// Represents the application state pub struct AppState { pub db: Database, } @@ -50,12 +51,18 @@ pub struct PostData { pub body: String, } +/// Custom error types for the application. pub enum AppError { + /// Error indicating that a requested resource was not found. NotFound(String), + /// Error indicating an internal server error occurred. InternalServerError(String), } impl IntoResponse for AppError { + /// Convert the error into an HTTP response. + /// + /// Maps the error variant to the corresponding HTTP status code and message. fn into_response(self) -> axum::response::Response { match self { AppError::NotFound(msg) => (StatusCode::NOT_FOUND, msg).into_response(), @@ -63,4 +70,3 @@ impl IntoResponse for AppError { } } } - diff --git a/mock-api/src/main.rs b/mock-api/src/main.rs index abe3b6d..e213ca7 100644 --- a/mock-api/src/main.rs +++ b/mock-api/src/main.rs @@ -23,9 +23,14 @@ async fn main() { .with(tracing_subscriber::fmt::layer()) .init(); + // The delay is expressed in milliseconds + // Used to add a delay for each request + // with the aim to "simulate" real world let delay = env_default("MOCK_SERVER_DELAY", 5); let delay = Duration::from_millis(delay); + // Number of requests the server can handle in a given moment + // after that number the server triggers rate-limiting let burst_size = env_default("MOCK_SERVER_BURST_SIZE", 1000); let rate_limiter_config = Arc::new( @@ -37,8 +42,10 @@ async fn main() { .unwrap(), ); + // Shared state of the API, used to keep the data that will be served let state = Arc::new(AppState::default()); + // The router and the available endpoints let mut router = Router::new() .route( "/", @@ -50,6 +57,7 @@ async fn main() { .route("/users/:user_id", get(mock_api::routes::get_user::handle)) .route("/reset", post(mock_api::routes::reset_database::handle)) .layer(axum::middleware::from_fn( + // This middleware is responsible to apply the delay functionality move |request: Request, next: Next| { let delay = delay.clone(); async move { @@ -61,6 +69,7 @@ async fn main() { )) .with_state(state); + // Check if rate limiting is enabled and apply it if env_default("MOCK_SERVER_LIMITER_ENABLED", false) { router = router.layer(GovernorLayer { config: rate_limiter_config, diff --git a/mock-api/src/routes/get_post.rs b/mock-api/src/routes/get_post.rs index df86fd6..e87581a 100644 --- a/mock-api/src/routes/get_post.rs +++ b/mock-api/src/routes/get_post.rs @@ -8,6 +8,7 @@ use axum::{ use crate::{AppError, AppState}; +/// route handler for getting a post pub async fn handle( state: State>, post_id: Path, diff --git a/mock-api/src/routes/get_posts.rs b/mock-api/src/routes/get_posts.rs index 46d37a6..63628db 100644 --- a/mock-api/src/routes/get_posts.rs +++ b/mock-api/src/routes/get_posts.rs @@ -4,6 +4,7 @@ use axum::{extract::State, response::IntoResponse, Json}; use crate::{AppError, AppState}; +/// route handler for getting all posts pub async fn handle(state: State>) -> Result { Ok(Json(state.db.posts())) } diff --git a/mock-api/src/routes/get_user.rs b/mock-api/src/routes/get_user.rs index ba34b68..dbaf54f 100644 --- a/mock-api/src/routes/get_user.rs +++ b/mock-api/src/routes/get_user.rs @@ -8,6 +8,7 @@ use axum::{ use crate::{AppError, AppState}; +/// route handler for getting a user pub async fn handle( state: State>, user_id: Path, diff --git a/mock-api/src/routes/get_users.rs b/mock-api/src/routes/get_users.rs index aba1e0b..93f9316 100644 --- a/mock-api/src/routes/get_users.rs +++ b/mock-api/src/routes/get_users.rs @@ -8,6 +8,7 @@ use axum::{ use crate::{AppError, AppState}; +/// route handler for getting all users pub async fn handle( state: State>, Query(params): Query>, diff --git a/mock-api/src/routes/reset_database.rs b/mock-api/src/routes/reset_database.rs index 2892330..1659a66 100644 --- a/mock-api/src/routes/reset_database.rs +++ b/mock-api/src/routes/reset_database.rs @@ -5,6 +5,7 @@ use serde_json::json; use crate::{AppError, AppState}; +/// route handler for resetting the database pub async fn handle(state: State>) -> Result { match state.db.reset() { Ok(()) => Ok(Json(json!({"status": "Database reset successfully"}))), diff --git a/mock-api/src/utils.rs b/mock-api/src/utils.rs index e04aad0..c2da319 100644 --- a/mock-api/src/utils.rs +++ b/mock-api/src/utils.rs @@ -1,5 +1,6 @@ use std::str::FromStr; +/// Used to read variables from Environment pub fn env_default(name: &str, default_value: T) -> T { std::env::var(name) .ok()