Bit of a better path param interface

This commit is contained in:
soup 2025-02-02 19:15:36 -05:00
parent fd9322923b
commit 8bede90019
Signed by: soup
SSH key fingerprint: SHA256:GYxje8eQkJ6HZKzVWDdyOUF1TyDiprruGhE0Ym8qYDY
2 changed files with 32 additions and 10 deletions

View file

@ -3,7 +3,17 @@ use std::collections::HashMap;
use url::Url; use url::Url;
use urlpattern::{UrlPattern, UrlPatternInit, UrlPatternMatchInput}; use urlpattern::{UrlPattern, UrlPatternInit, UrlPatternMatchInput};
pub type PathParams = HashMap<String, Option<String>>; pub struct PathParams(HashMap<String, Option<String>>);
impl PathParams {
pub fn get(&self, name: &str) -> &str {
let s = match self.0.get(name) {
None => return "",
Some(s) => s,
};
s.as_ref().map(|s| s.as_str()).unwrap_or("")
}
}
struct UrlPatternWithInput { struct UrlPatternWithInput {
pathname: String, pathname: String,
@ -65,13 +75,13 @@ impl<T> Router<T> {
for (upwi, methods) in self.patterns.iter() { for (upwi, methods) in self.patterns.iter() {
let pattern = &upwi.pattern; let pattern = &upwi.pattern;
let result = pattern.exec(UrlPatternMatchInput::Url(url.clone())); let result = pattern.exec(UrlPatternMatchInput::Url(url.clone()));
let pathGroups = match result { let path_groups = match result {
Ok(Some(res)) => res.pathname.groups, Ok(Some(res)) => res.pathname.groups,
_ => continue, _ => continue,
}; };
if let Some(t) = methods.get(method) { if let Some(t) = methods.get(method) {
return Ok((t, pathGroups)); return Ok((t, PathParams(path_groups)));
} }
return Err(405); return Err(405);

View file

@ -11,6 +11,10 @@ pub type AnyError = Box<dyn Error + Send + Sync + 'static>;
pub type Result<T> = core::result::Result<T, AnyError>; pub type Result<T> = core::result::Result<T, AnyError>;
pub type Dbs = atelier::rusqlite_thread_pool::PoolSender; pub type Dbs = atelier::rusqlite_thread_pool::PoolSender;
pub struct RequestCtx {
dbs: Dbs,
path_params: atelier::router::PathParams,
}
fn migrate(connection: &mut rusqlite::Connection) -> Result<()> { fn migrate(connection: &mut rusqlite::Connection) -> Result<()> {
Ok(()) Ok(())
@ -23,7 +27,10 @@ fn init(connection: &mut rusqlite::Connection) -> rusqlite::Result<()> {
type Request = axum::extract::Request; type Request = axum::extract::Request;
type Response = axum::response::Response; type Response = axum::response::Response;
type Handler = Box< type Handler = Box<
dyn Fn(Request) -> Pin<Box<dyn Future<Output = Response> + Send + 'static>> dyn Fn(
Request,
RequestCtx,
) -> Pin<Box<dyn Future<Output = Response> + Send + 'static>>
+ Send + Send
+ Sync + Sync
+ 'static, + 'static,
@ -33,18 +40,22 @@ type Router = atelier::router::Router<Handler>;
fn make_handler<Fut, F>(f: F) -> Handler fn make_handler<Fut, F>(f: F) -> Handler
where where
Fut: Future<Output = Response> + Send + 'static, Fut: Future<Output = Response> + Send + 'static,
F: FnMut(Request) -> Fut + Clone + Send + Sync + 'static, F: FnMut(Request, RequestCtx) -> Fut + Clone + Send + Sync + 'static,
{ {
Box::new(move |req| { Box::new(move |req, ctx| {
let mut f = f.clone(); let mut f = f.clone();
Box::pin(async move { f(req).await }) Box::pin(async move { f(req, ctx).await })
}) })
} }
async fn get_hello(req: Request) -> Response { async fn get_hello(req: Request, ctx: RequestCtx) -> Response {
"hello".into_response() "hello".into_response()
} }
async fn get_hello_name(req: Request, ctx: RequestCtx) -> Response {
format!("Hello, {}", ctx.path_params.get("name")).into_response()
}
fn make_router() -> Router { fn make_router() -> Router {
let mut router = atelier::router::Router::new(); let mut router = atelier::router::Router::new();
@ -55,6 +66,7 @@ fn make_router() -> Router {
} }
r!("GET", "/hello", get_hello); r!("GET", "/hello", get_hello);
r!("GET", "/hello/:name", get_hello_name);
router router
} }
@ -67,7 +79,7 @@ async fn serve(
let method = req.method().as_str(); let method = req.method().as_str();
let uri = format!("{}", req.uri()); let uri = format!("{}", req.uri());
let (handler, pathParams) = match router.get(method, &uri) { let (handler, path_params) = match router.get(method, &uri) {
Ok(h) => h, Ok(h) => h,
Err(sc) => { Err(sc) => {
return (http::status::StatusCode::from_u16(sc).unwrap(), "") return (http::status::StatusCode::from_u16(sc).unwrap(), "")
@ -75,7 +87,7 @@ async fn serve(
}, },
}; };
handler(req).await handler(req, RequestCtx { dbs, path_params }).await
} }
async fn go() -> Result<()> { async fn go() -> Result<()> {