diff --git a/Cargo.lock b/Cargo.lock index 355c463..73c955c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -395,7 +395,7 @@ dependencies = [ [[package]] name = "mock-server" -version = "1.0.1" +version = "1.1.0" dependencies = [ "axum", "clap", @@ -405,6 +405,7 @@ dependencies = [ "serde", "serde_json", "tokio", + "tower", "tower-http", "tracing", "tracing-subscriber", diff --git a/Cargo.toml b/Cargo.toml index b5b332e..17488f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ authors = ["yao "] edition = "2021" name = "mock-server" -version = "1.0.1" +version = "1.1.0" [dependencies] axum = "0.5.13" @@ -13,6 +13,7 @@ regex = "1.6.0" serde = {version = "1.0.141", features = ["derive"]} serde_json = "1.0.82" tokio = {version = "1.20.1", features = ["full"]} +tower = "0.4.13" tower-http = {version = "0.3.4", features = ["fs", "trace", "cors"]} tracing = "0.1.36" tracing-subscriber = {version = "0.3.15", features = ["registry", "fmt"]} diff --git a/src/app.rs b/src/app.rs index bc9008c..cf3e545 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,16 +1,18 @@ use crate::{ - models::{DataConfig, RoutingRule, Wrapper, WRAP_KEY_ERR, WRAP_KEY_OK}, + models::{DataConfig, RoutingRule, RoutingValue, Wrapper, WRAP_KEY_ERR, WRAP_KEY_OK}, service::*, util, Database, HashMap, }; use axum::{ - extract::{OriginalUri, Path, Query}, - http::{Method, StatusCode}, + body::Body, + extract::{FromRequest, Path, Query, RequestParts}, + http::{Method, Request, StatusCode}, response::IntoResponse, - routing::{any, get, get_service}, - Extension, Json, Router, + routing::{get, get_service}, + Extension, Form, Json, Router, }; use serde_json::Value; +use tower::service_fn; use tower_http::services::ServeDir; const DATA_QUERY_TPL: &str = "/api/([^/]*)$"; @@ -38,24 +40,51 @@ pub fn proxy(db: &Database) -> Router { tracing::debug!("routing {} to {:?}", key, v); let routing_value = v.clone(); let wrap = create_wrap(config, &routing_value.wrapping); - router = router.route( - key, - any( - |method: Method, - mut path: Path>, - query: Query>, - body: Json, - db: Extension, - wapper: Extension, - OriginalUri(original_uri): OriginalUri| async move { - tracing::debug!( - "original_uri = {original_uri}, method={method} path={:?}, query={:?}, body={:?}", - path, query, body - ); + router = router + .route( + key, + service_fn(|req: Request| async move { + let ex = req.extensions(); + let db = Extension(ex.get::().cloned().unwrap()); + let wrap = Extension(ex.get::().cloned().unwrap()); + let Extension(routing_value) = + Extension(ex.get::().cloned().unwrap()); + let uri = req.uri(); + tracing::info!("uri={}", uri); + + let mut req_parts = RequestParts::new(req); + + let query = Query::>::from_request(&mut req_parts) + .await + .unwrap(); + let mut path = Path::>::from_request(&mut req_parts) + .await + .unwrap(); + + let mut body = Json(Value::Null); + + // process form body and convert it to json format + if let Ok(Form(v)) = + Form::>::from_request(&mut req_parts).await + { + let mut map = serde_json::Map::new(); + for (key, value) in v { + map.insert(key, value.into()); + } + + body = Json(serde_json::Value::Object(map)); + } + // process json body + if let Ok(v) = Json::::from_request(&mut req_parts).await { + body = v; + } + + let method = req_parts.method(); // 检查规则 if let Err(err) = validate_rules(routing_value.rules, &path, &query, &body) { - return util::wrap_result(Err(err), Some(wapper.0)).into_response(); + let res = util::wrap_result(Err(err), Some(wrap.0)).into_response(); + return Ok(res); } // match the template let re = regex::Regex::new(DATA_QUERY_TPL).unwrap(); @@ -66,13 +95,14 @@ pub fn proxy(db: &Database) -> Router { } let new_query = create_query(query, routing_value.query); - return query_data(path, Query(new_query), db.clone()) + let res = query_data(path, Query(new_query), db.clone()) .await .into_response(); + return Ok(res); } let re = regex::Regex::new(DATA_ID_TPL).unwrap(); - if let Some(cap) = re.captures(&routing_value.to) { + if let Some(cap) = re.captures(&routing_value.to) { let data = cap.get(1).unwrap().as_str(); let id = cap.get(2).unwrap().as_str(); if !data.starts_with(":") { @@ -82,19 +112,24 @@ pub fn proxy(db: &Database) -> Router { if !id.starts_with(":") { path.insert("id".to_string(), id.to_string()); } - return match method { - Method::GET => get_data(path, db, wapper).await.into_response(), - Method::POST => post_data(path, body, db, wapper).await.into_response(), - Method::PUT => put_data(path, body, db, wapper).await.into_response(), - Method::DELETE => delete_data(path, db, wapper).await.into_response(), - _ => (StatusCode::METHOD_NOT_ALLOWED, "method not support").into_response(), - } + let res = match method { + &Method::GET => get_data(path, db, wrap).await.into_response(), + &Method::POST => post_data(path, body, db, wrap).await.into_response(), + &Method::PUT => put_data(path, body, db, wrap).await.into_response(), + &Method::DELETE => delete_data(path, db, wrap).await.into_response(), + _ => (StatusCode::METHOD_NOT_ALLOWED, "method not support") + .into_response(), + }; + + return Ok(res); } - (StatusCode::BAD_REQUEST, "bad request").into_response() - }, - ), - ).layer(Extension(wrap)) + let res = (StatusCode::BAD_REQUEST, "bad request").into_response(); + Ok(res) + }), + ) + .layer(Extension(wrap)) + .layer(Extension(routing_value)) } router diff --git a/src/models/mod.rs b/src/models/mod.rs index 0bdcfe0..40463a7 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -14,7 +14,7 @@ pub const WRAP_PAGE_PAGE: &str = "$page"; pub const WRAP_PAGE_SIZE: &str = "$size"; pub const WRAP_PAGE_ITEMS: &str = "$items"; -pub use data_config::{DataConfig, RoutingRule}; +pub use data_config::{DataConfig, RoutingRule, RoutingValue}; pub use named_query::NamedQuery; use serde_json::Value; pub type Wrapper = HashMap; diff --git a/static/db.json b/static/db.json index 8706051..e9091be 100644 --- a/static/db.json +++ b/static/db.json @@ -3,7 +3,9 @@ "config": { "routing": { - + "/fbpm_demo/api/expense/listByPageTask": { + "to": "/api/data2" + }, "/a/b/c/:id": { "to": "/api/data/:id" },