rama_http/service/web/endpoint/extract/
query.rs1use super::{FromPartsStateRefPair, OptionalFromPartsStateRefPair};
4use crate::request::Parts;
5use crate::utils::macros::define_http_rejection;
6use rama_net::uri::Uri;
7use serde::de::DeserializeOwned;
8
9#[derive(Debug, Clone)]
13pub struct Query<T>(pub T);
14
15define_http_rejection! {
16 #[status = BAD_REQUEST]
17 #[body = "Failed to deserialize query string"]
18 pub struct FailedToDeserializeQueryString(Error);
21}
22
23impl<T> Query<T>
24where
25 T: DeserializeOwned + Send + Sync + 'static,
26{
27 #[inline(always)]
29 pub fn try_from_uri(value: &Uri) -> Result<Self, FailedToDeserializeQueryString> {
30 value
31 .query_params::<T>()
32 .map(Self)
33 .map_err(FailedToDeserializeQueryString::from_err)
34 }
35
36 pub fn parse_query_str(query: &str) -> Result<Self, FailedToDeserializeQueryString> {
40 let params =
41 serde_html_form::from_str(query).map_err(FailedToDeserializeQueryString::from_err)?;
42 Ok(Self(params))
43 }
44}
45
46impl<T, State> FromPartsStateRefPair<State> for Query<T>
47where
48 T: DeserializeOwned + Send + Sync + 'static,
49 State: Send + Sync,
50{
51 type Rejection = FailedToDeserializeQueryString;
52
53 async fn from_parts_state_ref_pair(
54 parts: &Parts,
55 _state: &State,
56 ) -> Result<Self, Self::Rejection> {
57 parts
58 .uri
59 .query_params::<T>()
60 .map(Self)
61 .map_err(FailedToDeserializeQueryString::from_err)
62 }
63}
64
65impl<T, State> OptionalFromPartsStateRefPair<State> for Query<T>
66where
67 T: DeserializeOwned + Send + Sync + 'static,
68 State: Send + Sync,
69{
70 type Rejection = FailedToDeserializeQueryString;
71
72 async fn from_parts_state_ref_pair(
73 parts: &Parts,
74 _state: &State,
75 ) -> Result<Option<Self>, Self::Rejection> {
76 match parts.uri.query() {
77 Some(_) => parts
78 .uri
79 .query_params::<T>()
80 .map(|params| Some(Self(params)))
81 .map_err(FailedToDeserializeQueryString::from_err),
82 None => Ok(None),
83 }
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90 use serde::Deserialize;
91
92 #[test]
93 fn test_try_from_uri() {
94 #[derive(Deserialize)]
95 struct TestQueryParams {
96 foo: Vec<String>,
97 bar: u32,
98 }
99 let uri: Uri = "http://example.com/path?foo=hello&bar=42&foo=goodbye"
100 .parse()
101 .unwrap();
102 let Query(TestQueryParams { foo, bar }) = Query::try_from_uri(&uri).unwrap();
103 assert_eq!(foo, [String::from("hello"), String::from("goodbye")]);
104 assert_eq!(bar, 42);
105 }
106
107 #[test]
108 fn test_try_from_uri_with_invalid_query() {
109 #[derive(Deserialize)]
110 struct TestQueryParams {
111 _foo: String,
112 _bar: u32,
113 }
114 let uri: Uri = "http://example.com/path?foo=hello&bar=invalid"
115 .parse()
116 .unwrap();
117 let result: Result<Query<TestQueryParams>, _> = Query::try_from_uri(&uri);
118
119 assert!(result.is_err());
120 }
121}