use std::marker::PhantomData;
use std::ops::Deref;
use std::str::FromStr;
use serde::de::DeserializeOwned;
use validator::Validate;
use crate::web::{Error, RequestContext};
pub struct Inject<T: Send + Sync + 'static> {
inner: &'static T,
_marker: PhantomData<T>,
}
impl<T: Send + Sync + 'static> Inject<T> {
#[inline]
pub fn from_ctx(ctx: &RequestContext) -> Self {
Self {
inner: ctx.inject::<T>(),
_marker: PhantomData,
}
}
#[doc(hidden)]
#[inline]
pub fn __from_static(inner: &'static T) -> Self {
Self {
inner,
_marker: PhantomData,
}
}
#[inline]
pub fn get(&self) -> &'static T {
self.inner
}
}
impl<T: Send + Sync + 'static> Deref for Inject<T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
self.inner
}
}
impl<T: Send + Sync + 'static> Clone for Inject<T> {
#[inline]
fn clone(&self) -> Self {
Self {
inner: self.inner,
_marker: PhantomData,
}
}
}
#[inline]
pub fn extract_param<T: FromStr>(ctx: &RequestContext, name: &'static str) -> Result<T, Error> {
let raw = ctx
.param(name)
.ok_or(Error::BadRequest("missing path parameter"))?;
raw.parse::<T>()
.map_err(|_| Error::BadRequest("invalid path parameter"))
}
#[inline]
pub fn extract_query<T: DeserializeOwned>(ctx: &RequestContext) -> Result<T, Error> {
let raw = ctx.query_string().unwrap_or("");
serde_urlencoded::from_str::<T>(raw).map_err(|_| Error::BadRequest("invalid query string"))
}
#[inline]
pub fn extract_body_json<T: DeserializeOwned>(ctx: &RequestContext) -> Result<T, Error> {
serde_json::from_slice::<T>(ctx.body()).map_err(|_| Error::BadRequest("invalid JSON body"))
}
#[inline]
pub fn extract_header<'a>(ctx: &'a RequestContext, name: &'static str) -> Result<&'a str, Error> {
ctx.header(name)
.ok_or(Error::BadRequest("missing required header"))
}
#[inline]
pub fn extract_body_validated<T: DeserializeOwned + Validate>(
ctx: &RequestContext,
) -> Result<T, Error> {
let v: T = extract_body_json(ctx)?;
v.validate().map_err(Error::from)?;
Ok(v)
}
#[inline]
pub fn extract_query_validated<T: DeserializeOwned + Validate>(
ctx: &RequestContext,
) -> Result<T, Error> {
let v: T = extract_query(ctx)?;
v.validate().map_err(Error::from)?;
Ok(v)
}