use super::IntoResponse;
#[cfg(feature = "openapi")]
use crate::ResponseSchema;
use crate::{Response, ResponseBody};
use futures_util::future::{self, FutureExt};
use gotham::{
hyper::{
header::{HeaderMap, HeaderValue, IntoHeaderName},
StatusCode
},
mime::{Mime, APPLICATION_JSON}
};
#[cfg(feature = "openapi")]
use openapi_type::OpenapiSchema;
use std::{fmt::Debug, future::Future, pin::Pin};
#[derive(Clone, Debug, Default)]
pub struct Success<T> {
value: T,
headers: HeaderMap
}
impl<T> From<T> for Success<T> {
fn from(t: T) -> Self {
Self {
value: t,
headers: HeaderMap::new()
}
}
}
impl<T> Success<T> {
pub fn header<K: IntoHeaderName>(&mut self, name: K, value: HeaderValue) {
self.headers.insert(name, value);
}
pub fn headers_mut(&mut self) -> &mut HeaderMap {
&mut self.headers
}
}
impl<T: ResponseBody> IntoResponse for Success<T> {
type Err = serde_json::Error;
fn into_response(self) -> Pin<Box<dyn Future<Output = Result<Response, Self::Err>> + Send>> {
let res = serde_json::to_string(&self.value)
.map(|body| Response::json(StatusCode::OK, body).with_headers(self.headers));
future::ready(res).boxed()
}
fn accepted_types() -> Option<Vec<Mime>> {
Some(vec![APPLICATION_JSON])
}
}
#[cfg(feature = "openapi")]
impl<T: ResponseBody> ResponseSchema for Success<T> {
fn schema(code: StatusCode) -> OpenapiSchema {
assert_eq!(code, StatusCode::OK);
T::schema()
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::response::OrAllTypes;
use futures_executor::block_on;
use gotham::hyper::header::ACCESS_CONTROL_ALLOW_ORIGIN;
#[derive(Debug, Default, Serialize)]
#[cfg_attr(feature = "openapi", derive(openapi_type::OpenapiType))]
struct Msg {
msg: String
}
#[test]
fn success_always_successfull() {
let success: Success<Msg> = Msg::default().into();
let res = block_on(success.into_response()).expect("didn't expect error response");
assert_eq!(res.status, StatusCode::OK);
assert_eq!(res.mime, Some(APPLICATION_JSON));
assert_eq!(res.full_body().unwrap(), br#"{"msg":""}"#);
#[cfg(feature = "openapi")]
assert_eq!(<Success<Msg>>::status_codes(), vec![StatusCode::OK]);
}
#[test]
fn success_custom_headers() {
let mut success: Success<Msg> = Msg::default().into();
success.header(ACCESS_CONTROL_ALLOW_ORIGIN, HeaderValue::from_static("*"));
let res = block_on(success.into_response()).expect("didn't expect error response");
let cors = res.headers.get(ACCESS_CONTROL_ALLOW_ORIGIN);
assert_eq!(cors.map(|value| value.to_str().unwrap()), Some("*"));
}
#[test]
fn success_accepts_json() {
assert!(
<Success<Msg>>::accepted_types()
.or_all_types()
.contains(&APPLICATION_JSON)
)
}
}