diff --git a/examples/key_value_store.rs b/examples/key_value_store.rs index 8447cee5..324b3de4 100644 --- a/examples/key_value_store.rs +++ b/examples/key_value_store.rs @@ -52,7 +52,7 @@ struct State { async fn get( _req: Request<Body>, - params: extract::UrlParams, + params: extract::UrlParamsMap, state: extract::Extension<SharedState>, ) -> Result<Bytes, Error> { let state = state.into_inner(); @@ -69,7 +69,7 @@ async fn get( async fn set( _req: Request<Body>, - params: extract::UrlParams, + params: extract::UrlParamsMap, value: extract::BytesMaxLength<{ 1024 * 5_000 }>, // ~5mb state: extract::Extension<SharedState>, ) -> Result<response::Empty, Error> { diff --git a/src/error.rs b/src/error.rs index fcfae63c..dcfa50bc 100644 --- a/src/error.rs +++ b/src/error.rs @@ -39,6 +39,9 @@ pub enum Error { #[error("response failed with status {0}")] Status(StatusCode), + #[error("invalid URL param. Expected something of type `{type_name}`")] + InvalidUrlParam { type_name: &'static str }, + #[error("unknown URL param `{0}`")] UnknownUrlParam(String), } @@ -65,7 +68,8 @@ where match error { Error::DeserializeRequestBody(_) | Error::QueryStringMissing - | Error::DeserializeQueryString(_) => make_response(StatusCode::BAD_REQUEST), + | Error::DeserializeQueryString(_) + | Error::InvalidUrlParam { .. } => make_response(StatusCode::BAD_REQUEST), Error::Status(status) => make_response(status), diff --git a/src/extract.rs b/src/extract.rs index 998bc232..d1c6b41c 100644 --- a/src/extract.rs +++ b/src/extract.rs @@ -184,9 +184,9 @@ impl<const N: u64> FromRequest for BytesMaxLength<N> { } } -pub struct UrlParams(HashMap<String, String>); +pub struct UrlParamsMap(HashMap<String, String>); -impl UrlParams { +impl UrlParamsMap { pub fn get(&self, key: &str) -> Result<&str, Error> { if let Some(value) = self.0.get(key) { Ok(value) @@ -194,9 +194,18 @@ impl UrlParams { Err(Error::UnknownUrlParam(key.to_string())) } } + + pub fn get_typed<T>(&self, key: &str) -> Result<T, Error> + where + T: std::str::FromStr, + { + self.get(key)?.parse().map_err(|_| Error::InvalidUrlParam { + type_name: std::any::type_name::<T>(), + }) + } } -impl FromRequest for UrlParams { +impl FromRequest for UrlParamsMap { type Future = future::Ready<Result<Self, Error>>; fn from_request(req: &mut Request<Body>) -> Self::Future {