arcly_http/web/
extract.rs1use std::marker::PhantomData;
9use std::ops::Deref;
10use std::str::FromStr;
11
12use serde::de::DeserializeOwned;
13use validator::Validate;
14
15use crate::web::{Error, RequestContext};
16
17pub struct Inject<T: Send + Sync + 'static> {
20 inner: &'static T,
21 _marker: PhantomData<T>,
22}
23
24impl<T: Send + Sync + 'static> Inject<T> {
25 #[inline]
26 pub fn from_ctx(ctx: &RequestContext) -> Self {
27 Self {
28 inner: ctx.inject::<T>(),
29 _marker: PhantomData,
30 }
31 }
32 #[doc(hidden)]
35 #[inline]
36 pub fn __from_static(inner: &'static T) -> Self {
37 Self {
38 inner,
39 _marker: PhantomData,
40 }
41 }
42 #[inline]
43 pub fn get(&self) -> &'static T {
44 self.inner
45 }
46}
47
48impl<T: Send + Sync + 'static> Deref for Inject<T> {
49 type Target = T;
50 #[inline]
51 fn deref(&self) -> &T {
52 self.inner
53 }
54}
55
56impl<T: Send + Sync + 'static> Clone for Inject<T> {
57 #[inline]
58 fn clone(&self) -> Self {
59 Self {
60 inner: self.inner,
61 _marker: PhantomData,
62 }
63 }
64}
65
66#[inline]
72pub fn extract_param<T: FromStr>(ctx: &RequestContext, name: &'static str) -> Result<T, Error> {
73 let raw = ctx
74 .param(name)
75 .ok_or(Error::BadRequest("missing path parameter"))?;
76 raw.parse::<T>()
77 .map_err(|_| Error::BadRequest("invalid path parameter"))
78}
79
80#[inline]
81pub fn extract_query<T: DeserializeOwned>(ctx: &RequestContext) -> Result<T, Error> {
82 let raw = ctx.query_string().unwrap_or("");
83 serde_urlencoded::from_str::<T>(raw).map_err(|_| Error::BadRequest("invalid query string"))
84}
85
86#[inline]
87pub fn extract_body_json<T: DeserializeOwned>(ctx: &RequestContext) -> Result<T, Error> {
88 serde_json::from_slice::<T>(ctx.body()).map_err(|_| Error::BadRequest("invalid JSON body"))
89}
90
91#[inline]
92pub fn extract_header<'a>(ctx: &'a RequestContext, name: &'static str) -> Result<&'a str, Error> {
93 ctx.header(name)
94 .ok_or(Error::BadRequest("missing required header"))
95}
96
97#[inline]
104pub fn extract_body_validated<T: DeserializeOwned + Validate>(
105 ctx: &RequestContext,
106) -> Result<T, Error> {
107 let v: T = extract_body_json(ctx)?;
108 v.validate().map_err(Error::from)?;
109 Ok(v)
110}
111
112#[inline]
113pub fn extract_query_validated<T: DeserializeOwned + Validate>(
114 ctx: &RequestContext,
115) -> Result<T, Error> {
116 let v: T = extract_query(ctx)?;
117 v.validate().map_err(Error::from)?;
118 Ok(v)
119}