Skip to content

Commit

Permalink
Expose the matched route as a method on the request struct
Browse files Browse the repository at this point in the history
If the router found a matching route we store it as an extension struct
on the request and then expose it to the user as a method on `Request`.

Signed-off-by: Johannes Löthberg <[email protected]>
  • Loading branch information
kyrias committed Sep 8, 2022
1 parent e79e4f6 commit 6ed507b
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 5 deletions.
21 changes: 20 additions & 1 deletion src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use async_std::io::{self, prelude::*};
use async_std::task::{Context, Poll};
use routefinder::Captures;

use std::ops::Index;
use std::ops::{Deref, Index};
use std::pin::Pin;

#[cfg(feature = "cookies")]
Expand All @@ -12,6 +12,7 @@ use crate::http::cookies::Cookie;
use crate::http::format_err;
use crate::http::headers::{self, HeaderName, HeaderValues, ToHeaderValues};
use crate::http::{self, Body, Method, Mime, StatusCode, Url, Version};
use crate::route::MatchedRoute;
use crate::Response;

pin_project_lite::pin_project! {
Expand Down Expand Up @@ -266,6 +267,24 @@ impl<State> Request<State> {
&self.state
}

/// Get the matched route.
///
/// Returns the route as a `&str`, borrowed from this `Request`.
///
/// # Examples
///
/// ```
/// # use tide::Request;
/// let mut app = tide::Server::new();
/// app.at("/route").get(|req: Request<()>| async move {
/// let route = req.route().unwrap_or("No route found");
/// Ok(route.to_string())
/// });
/// ```
pub fn route(&self) -> Option<&str> {
self.ext::<MatchedRoute>().map(|r| r.deref())
}

/// Extract and parse a route parameter by name.
///
/// Returns the parameter as a `&str`, borrowed from this `Request`.
Expand Down
12 changes: 12 additions & 0 deletions src/route.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,18 @@ use crate::{router::Router, Endpoint, Middleware};

use kv_log_macro::trace;

/// Extension struct for storing the matched route in the request.
#[derive(Debug)]
pub(crate) struct MatchedRoute(pub(crate) String);

impl std::ops::Deref for MatchedRoute {
type Target = str;

fn deref(&self) -> &Self::Target {
&self.0
}
}

/// A handle to a route.
///
/// All HTTP requests are made against resources. After using [`Server::at`] (or
Expand Down
5 changes: 5 additions & 0 deletions src/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ impl<State> std::fmt::Debug for Router<State> {
pub(crate) struct Selection<'a, State> {
pub(crate) endpoint: &'a DynEndpoint<State>,
pub(crate) params: Captures<'static, 'static>,
pub(crate) matched_route: Option<String>,
}

impl<State: Clone + Send + Sync + 'static> Router<State> {
Expand Down Expand Up @@ -63,11 +64,13 @@ impl<State: Clone + Send + Sync + 'static> Router<State> {
Selection {
endpoint: m.handler(),
params: m.captures().into_owned(),
matched_route: Some(m.route().to_string()),
}
} else if let Some(m) = self.all_method_router.best_match(path) {
Selection {
endpoint: m.handler(),
params: m.captures().into_owned(),
matched_route: Some(m.route().to_string()),
}
} else if method == http_types::Method::Head {
// If it is a HTTP HEAD request then check if there is a callback in the endpoints map
Expand All @@ -85,11 +88,13 @@ impl<State: Clone + Send + Sync + 'static> Router<State> {
Selection {
endpoint: &method_not_allowed,
params: Captures::default(),
matched_route: None,
}
} else {
Selection {
endpoint: &not_found_endpoint,
params: Captures::default(),
matched_route: None,
}
}
}
Expand Down
25 changes: 21 additions & 4 deletions src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use kv_log_macro::{info, trace};
use crate::cookies;
use crate::listener::{Listener, ToListener};
use crate::middleware::{Middleware, Next};
use crate::route::MatchedRoute;
use crate::router::{Router, Selection};
use crate::{Endpoint, Request, Route};

Expand Down Expand Up @@ -287,9 +288,17 @@ where
} = self.clone();

let method = req.method().to_owned();
let Selection { endpoint, params } = router.route(req.url().path(), method);
let Selection {
endpoint,
params,
matched_route,
} = router.route(req.url().path(), method);
let route_params = vec![params];
let req = Request::new(state, req, route_params);
let mut req = Request::new(state, req, route_params);

if let Some(route) = matched_route {
req.set_ext(MatchedRoute(route));
}

let next = Next {
endpoint,
Expand Down Expand Up @@ -349,9 +358,17 @@ impl<State: Clone + Sync + Send + 'static, InnerState: Clone + Sync + Send + 'st
let middleware = self.middleware.clone();
let state = self.state.clone();

let Selection { endpoint, params } = router.route(&path, method);
let Selection {
endpoint,
params,
matched_route,
} = router.route(&path, method);
route_params.push(params);
let req = Request::new(state, req, route_params);
let mut req = Request::new(state, req, route_params);

if let Some(route) = matched_route {
req.set_ext(MatchedRoute(route));
}

let next = Next {
endpoint,
Expand Down

0 comments on commit 6ed507b

Please sign in to comment.