Skip to content

Commit

Permalink
Added path normalization service with tower-http
Browse files Browse the repository at this point in the history
  • Loading branch information
ezrasingh committed Aug 12, 2024
1 parent 04e6941 commit 41f6c1d
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 36 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion geoprox-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ axum = { version = "0.7.5", features = ["macros"] }
serde = { version = "1.0.199", features = ["derive", "rc"] }
serde_json = "1.0.116"
tokio = { version = "1.37.0", features = ["full"] }
tower-http = { version = "0.5.2", features = ["fs", "trace"] }
tower = "0.4.13"
tower-http = { version = "0.5.2", features = ["fs", "trace", "normalize-path"] }
tracing = "0.1.40"
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
utoipa = { version = "4.2.3", features = ["axum_extras"] }
Expand Down
26 changes: 13 additions & 13 deletions geoprox-server/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,24 @@ pub fn routes(app_state: AppState) -> Router {

Router::new()
.nest(
"/geohash/",
"/geohash",
Router::new()
.route("/", get(geohash_api::encode_latlng))
.route("/:ghash/", get(geohash_api::decode_geohash))
.route("/:ghash/neighbors/", get(geohash_api::get_neighbors))
.route("/:ghash", get(geohash_api::decode_geohash))
.route("/:ghash/neighbors", get(geohash_api::get_neighbors))
.layer(axum::middleware::from_fn(set_cache_control)),
)
.route(
"/shard/:index/",
"/shard/:index",
post(geoshard_api::create_index)
.delete(geoshard_api::drop_index)
.put(geoshard_api::insert_key)
.patch(geoshard_api::remove_key)
.get(geoshard_api::query_range),
)
.route("/shard/", get(geoshard_api::query_range_many))
.route("/shard", get(geoshard_api::query_range_many))
.route(
"/shard/:index/batch/",
"/shard/:index/batch",
put(geoshard_api::insert_key_batch).patch(geoshard_api::remove_key_batch),
)
.layer(axum::middleware::from_fn(json_content))
Expand Down Expand Up @@ -123,16 +123,16 @@ mod test {
use serde_json::json;

fn setup() -> TestServer {
let app = Router::new().nest("/api/v1/", routes(AppState::default()));
let router = Router::new().nest("/api/v1/", routes(AppState::default()));
let config = TestServerConfig::builder().build();
TestServer::new_with_config(app, config).unwrap()
TestServer::new_with_config(router, config).unwrap()
}

#[tokio::test]
async fn can_geohash_api() {
let server = setup();
let req = server
.get("/api/v1/geohash/")
.get("/api/v1/geohash")
.add_query_params(dto::EncodeLatLng {
lat: 45.0,
lng: 45.0,
Expand All @@ -151,17 +151,17 @@ mod test {
#[tokio::test]
async fn can_range_query_api() {
let server = setup();
server.post("/api/v1/shard/drivers/").await;
server.post("/api/v1/shard/drivers").await;
server
.put("/api/v1/shard/drivers/")
.put("/api/v1/shard/drivers")
.json(&json!({ "key": "Alice", "lat": 1.0, "lng": 0.0 }))
.await;
server
.put("/api/v1/geoshard/drivers/")
.put("/api/v1/geoshard/drivers")
.json(&json!({ "key": "Bob", "lat": 0.0, "lng": 1.0 }))
.await;
let res = server
.get("/api/v1/shard/drivers/")
.get("/api/v1/shard/drivers")
.add_query_params(json!({
"lat": 0.0, "lng": 0.0, "range": 1000
}))
Expand Down
22 changes: 11 additions & 11 deletions geoprox-server/src/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub mod geohash_api {
/// Decode geohash by path param, returns coordinates with precision estimates.
#[utoipa::path(
get,
path = "/api/v1/geohash/{ghash}/",
path = "/api/v1/geohash/{ghash}",
params(
("ghash" = String, Path, description = "Geohash encoded region"),
),
Expand Down Expand Up @@ -43,7 +43,7 @@ pub mod geohash_api {
/// Encode coordinates by query params, returns geohash.
#[utoipa::path(
get,
path = "/api/v1/geohash/",
path = "/api/v1/geohash",
params(EncodeLatLng),
responses(
(
Expand All @@ -68,7 +68,7 @@ pub mod geohash_api {
/// Returns geohash neighbors in all cardinal directions.
#[utoipa::path(
get,
path = "/api/v1/geohash/{ghash}/neighbors/",
path = "/api/v1/geohash/{ghash}/neighbors",
params(
("ghash" = String, Path, description = "Geohash encoded region"),
),
Expand Down Expand Up @@ -107,7 +107,7 @@ pub mod geoshard_api {
/// Creates an in-memory index within this geoshard
#[utoipa::path(
post,
path = "/api/v1/shard/{index}/",
path = "/api/v1/shard/{index}",
params(
("index" = String, Path, description = "Geospatial index name"),
),
Expand Down Expand Up @@ -148,7 +148,7 @@ pub mod geoshard_api {
/// Drop index. All keys will be lost
#[utoipa::path(
delete,
path = "/api/v1/shard/{index}/",
path = "/api/v1/shard/{index}",
params(
("index" = String, Path, description = "Geospatial index name"),
),
Expand Down Expand Up @@ -176,7 +176,7 @@ pub mod geoshard_api {
/// Inserts key into geospatial index
#[utoipa::path(
put,
path = "/api/v1/shard/{index}/",
path = "/api/v1/shard/{index}",
params(
("index" = String, Path, description = "Geospatial index name"),
),
Expand Down Expand Up @@ -212,7 +212,7 @@ pub mod geoshard_api {
/// Inserts multiple keys into geospatial index
#[utoipa::path(
put,
path = "/api/v1/shard/{index}/batch/",
path = "/api/v1/shard/{index}/batch",
params(
("index" = String, Path, description = "Geospatial index name"),
),
Expand Down Expand Up @@ -252,7 +252,7 @@ pub mod geoshard_api {
/// Removes key from geospatial index
#[utoipa::path(
patch,
path = "/api/v1/shard/{index}/",
path = "/api/v1/shard/{index}",
params(
("index" = String, Path, description = "Geospatial index name"),
),
Expand Down Expand Up @@ -285,7 +285,7 @@ pub mod geoshard_api {
/// Removes multiple keys from geospatial index
#[utoipa::path(
patch,
path = "/api/v1/shard/{index}/batch/",
path = "/api/v1/shard/{index}/batch",
params(
("index" = String, Path, description = "Geospatial index name"),
),
Expand Down Expand Up @@ -323,7 +323,7 @@ pub mod geoshard_api {
/// Search geospatial index for all keys within some distance
#[utoipa::path(
get,
path = "/api/v1/shard/{index}/",
path = "/api/v1/shard/{index}",
params(
("index" = String, Path, description = "Geospatial index name"),
QueryRange
Expand Down Expand Up @@ -360,7 +360,7 @@ pub mod geoshard_api {
/// Search geospatial many indices for all keys within some distance
#[utoipa::path(
get,
path = "/api/v1/shard/",
path = "/api/v1/shard",
params(QueryRangeMany),
responses(
(
Expand Down
27 changes: 17 additions & 10 deletions geoprox-server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ use app::AppState;
use config::ServerConfig;
use geoprox_core::models::GeoShardConfig;

use axum::extract::Request;
use axum::routing::Router;
use tower_http::trace::TraceLayer;
use tower::Layer;
use tower_http::normalize_path::NormalizePathLayer;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};

/// Start http server
Expand All @@ -24,17 +26,22 @@ pub async fn run(server_config: ServerConfig, shard_config: GeoShardConfig) {
.with(tracing_subscriber::fmt::layer())
.init();

let socket: std::net::SocketAddr = server_config.clone().into();
let listener = tokio::net::TcpListener::bind(socket).await.unwrap();

let app = AppState::new(server_config, shard_config);
let state = AppState::new(server_config.clone(), shard_config);
let router = Router::new()
.nest(
"/api/v1/",
api::routes(app).layer(TraceLayer::new_for_http()),
)
.nest("/api/v1/", api::routes(state))
.merge(api::docs::router());

// normalize paths on all routes
let router = NormalizePathLayer::trim_trailing_slash().layer(router);

let socket: std::net::SocketAddr = server_config.into();
let listener = tokio::net::TcpListener::bind(socket).await.unwrap();
println!("listening on {}", listener.local_addr().unwrap());
axum::serve(listener, router).await.unwrap();

axum::serve(
listener,
axum::ServiceExt::<Request>::into_make_service(router),
)
.await
.unwrap();
}
3 changes: 2 additions & 1 deletion geoprox-server/src/middleware.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use axum::{extract::Request, http::header, middleware::Next, response::IntoResponse};
use axum::extract::Request;
use axum::{http::header, middleware::Next, response::IntoResponse};

/// tells client to cache this response for some time
pub async fn set_cache_control(req: Request, next: Next) -> impl IntoResponse {
Expand Down

0 comments on commit 41f6c1d

Please sign in to comment.