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 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 {
pathname: String,
@ -65,13 +75,13 @@ impl<T> Router<T> {
for (upwi, methods) in self.patterns.iter() {
let pattern = &upwi.pattern;
let result = pattern.exec(UrlPatternMatchInput::Url(url.clone()));
let pathGroups = match result {
let path_groups = match result {
Ok(Some(res)) => res.pathname.groups,
_ => continue,
};
if let Some(t) = methods.get(method) {
return Ok((t, pathGroups));
return Ok((t, PathParams(path_groups)));
}
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 Dbs = atelier::rusqlite_thread_pool::PoolSender;
pub struct RequestCtx {
dbs: Dbs,
path_params: atelier::router::PathParams,
}
fn migrate(connection: &mut rusqlite::Connection) -> Result<()> {
Ok(())
@ -23,7 +27,10 @@ fn init(connection: &mut rusqlite::Connection) -> rusqlite::Result<()> {
type Request = axum::extract::Request;
type Response = axum::response::Response;
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
+ Sync
+ 'static,
@ -33,18 +40,22 @@ type Router = atelier::router::Router<Handler>;
fn make_handler<Fut, F>(f: F) -> Handler
where
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();
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()
}
async fn get_hello_name(req: Request, ctx: RequestCtx) -> Response {
format!("Hello, {}", ctx.path_params.get("name")).into_response()
}
fn make_router() -> Router {
let mut router = atelier::router::Router::new();
@ -55,6 +66,7 @@ fn make_router() -> Router {
}
r!("GET", "/hello", get_hello);
r!("GET", "/hello/:name", get_hello_name);
router
}
@ -67,7 +79,7 @@ async fn serve(
let method = req.method().as_str();
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,
Err(sc) => {
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<()> {