diff --git a/examples/http_service_match.rs b/examples/http_service_match.rs new file mode 100644 index 00000000..7d58ce2b --- /dev/null +++ b/examples/http_service_match.rs @@ -0,0 +1,77 @@ +//! This example demonstrates how to create a web router, +//! without the need of service boxing, as is the case with +//! the use of [`WebService`] as demonstrated in +//! the [`http_web_service_dir_and_api`] example. +//! +//! ```sh +//! cargo run --example http_service_match +//! ``` +//! +//! # Expected output +//! +//! The server will start and listen on `:8080`. You can use your browser to interact with the service: +//! +//! ```sh +//! open http://localhost:8080 +//! curl -v -X PATCH http://localhost:8080/echo +//! ``` +//! +//! You should see a the homepage in your browser. +//! The example will also respond to your request with the method and path of the request as JSON. + +// rama provides everything out of the box to build a complete web service. +use rama::{ + http::{ + layer::trace::TraceLayer, + matcher::{HttpMatcher, PathFilter}, + response::{Html, Json, Redirect}, + server::HttpServer, + service::web::match_service, + Request, + }, + rt::Executor, + service::ServiceBuilder, +}; + +use serde_json::json; +/// Everything else we need is provided by the standard library, community crates or tokio. +use tracing::level_filters::LevelFilter; +use tracing_subscriber::layer::SubscriberExt; +use tracing_subscriber::util::SubscriberInitExt; +use tracing_subscriber::{fmt, EnvFilter}; + +#[tokio::main] +async fn main() { + tracing_subscriber::registry() + .with(fmt::layer()) + .with( + EnvFilter::builder() + .with_default_directive(LevelFilter::DEBUG.into()) + .from_env_lossy(), + ) + .init(); + + let addr = "127.0.0.1:8080"; + tracing::info!("running service at: {addr}"); + let exec = Executor::default(); + HttpServer::auto(exec) + .listen( + addr, + ServiceBuilder::new() + .layer(TraceLayer::new_for_http()) + .service( + match_service!{ + HttpMatcher::method_get().and_path("/") => Html(r##"

Home

Echo Request"##.to_string()), + PathFilter::new("/echo") => |req: Request| async move { + Json(json!({ + "method": req.method().as_str(), + "path": req.uri().path(), + })) + }, + _ => Redirect::temporary("/"), + } + ), + ) + .await + .unwrap(); +} diff --git a/src/http/service/web/service.rs b/src/http/service/web/service.rs index 61535b33..e360b9e4 100644 --- a/src/http/service/web/service.rs +++ b/src/http/service/web/service.rs @@ -291,9 +291,10 @@ all_the_tuples_no_last_special_case!(impl_matcher_service_tuple); /// with the last tuple being the fallback service. And all services implement /// the [`IntoEndpointService`] trait. macro_rules! __match_service { - ($($M:expr => $S:expr),+, _ => $F:expr $(,)?) => { + ($($M:expr => $S:expr),+, _ => $F:expr $(,)?) => {{ + use $crate::http::service::web::IntoEndpointService; ($(($M, $S.into_endpoint_service())),+, $F.into_endpoint_service()) - }; + }}; } #[doc(inline)]