2020-05-01 14:48:11 +00:00
|
|
|
#[cfg(feature = "openapi")]
|
|
|
|
use crate::OpenapiSchema;
|
2020-09-15 15:10:41 +02:00
|
|
|
use crate::Response;
|
2020-05-01 14:48:11 +00:00
|
|
|
use futures_util::future::FutureExt;
|
2020-05-03 18:48:55 +02:00
|
|
|
use mime::{Mime, STAR_STAR};
|
2020-05-01 14:48:11 +00:00
|
|
|
use serde::Serialize;
|
|
|
|
use std::{
|
|
|
|
error::Error,
|
|
|
|
fmt::{Debug, Display},
|
2020-09-15 15:10:41 +02:00
|
|
|
future::Future,
|
2020-05-01 14:48:11 +00:00
|
|
|
pin::Pin
|
|
|
|
};
|
|
|
|
|
|
|
|
mod auth_result;
|
|
|
|
pub use auth_result::{AuthError, AuthErrorOrOther, AuthResult, AuthSuccess};
|
|
|
|
|
|
|
|
mod no_content;
|
|
|
|
pub use no_content::NoContent;
|
|
|
|
|
|
|
|
mod raw;
|
|
|
|
pub use raw::Raw;
|
|
|
|
|
2020-05-04 00:27:14 +02:00
|
|
|
#[allow(clippy::module_inception)]
|
2020-05-01 14:48:11 +00:00
|
|
|
mod result;
|
|
|
|
pub use result::IntoResponseError;
|
|
|
|
|
|
|
|
mod success;
|
|
|
|
pub use success::Success;
|
|
|
|
|
2020-09-15 15:10:41 +02:00
|
|
|
pub(crate) trait OrAllTypes {
|
2020-05-03 18:48:55 +02:00
|
|
|
fn or_all_types(self) -> Vec<Mime>;
|
|
|
|
}
|
|
|
|
|
2020-09-15 15:10:41 +02:00
|
|
|
impl OrAllTypes for Option<Vec<Mime>> {
|
|
|
|
fn or_all_types(self) -> Vec<Mime> {
|
2020-05-03 18:48:55 +02:00
|
|
|
self.unwrap_or_else(|| vec![STAR_STAR])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-01 14:48:11 +00:00
|
|
|
/// A trait provided to convert a resource's result to json.
|
2020-09-15 15:10:41 +02:00
|
|
|
pub trait ResourceResult {
|
|
|
|
type Err: Error + Send + Sync + 'static;
|
|
|
|
|
2020-05-01 14:48:11 +00:00
|
|
|
/// Turn this into a response that can be returned to the browser. This api will likely
|
|
|
|
/// change in the future.
|
|
|
|
fn into_response(self) -> Pin<Box<dyn Future<Output = Result<Response, Self::Err>> + Send>>;
|
2020-09-15 15:10:41 +02:00
|
|
|
|
2020-05-01 14:48:11 +00:00
|
|
|
/// Return a list of supported mime types.
|
2020-09-15 15:10:41 +02:00
|
|
|
fn accepted_types() -> Option<Vec<Mime>> {
|
2020-05-01 14:48:11 +00:00
|
|
|
None
|
|
|
|
}
|
2020-09-15 15:10:41 +02:00
|
|
|
|
2020-05-01 14:48:11 +00:00
|
|
|
#[cfg(feature = "openapi")]
|
|
|
|
fn schema() -> OpenapiSchema;
|
2020-09-15 15:10:41 +02:00
|
|
|
|
2020-05-01 14:48:11 +00:00
|
|
|
#[cfg(feature = "openapi")]
|
2020-09-15 15:10:41 +02:00
|
|
|
fn default_status() -> crate::StatusCode {
|
2020-05-01 14:48:11 +00:00
|
|
|
crate::StatusCode::OK
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "openapi")]
|
2020-09-15 15:10:41 +02:00
|
|
|
impl<Res: ResourceResult> crate::OpenapiType for Res {
|
|
|
|
fn schema() -> OpenapiSchema {
|
2020-05-01 14:48:11 +00:00
|
|
|
Self::schema()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// The default json returned on an 500 Internal Server Error.
|
|
|
|
#[derive(Debug, Serialize)]
|
2020-09-15 15:10:41 +02:00
|
|
|
pub(crate) struct ResourceError {
|
|
|
|
error: bool,
|
|
|
|
message: String
|
2020-05-01 14:48:11 +00:00
|
|
|
}
|
|
|
|
|
2020-09-15 15:10:41 +02:00
|
|
|
impl<T: ToString> From<T> for ResourceError {
|
|
|
|
fn from(message: T) -> Self {
|
2020-05-01 14:48:11 +00:00
|
|
|
Self {
|
|
|
|
error: true,
|
|
|
|
message: message.to_string()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-15 15:10:41 +02:00
|
|
|
fn into_response_helper<Err, F>(create_response: F) -> Pin<Box<dyn Future<Output = Result<Response, Err>> + Send>>
|
2020-05-01 14:48:11 +00:00
|
|
|
where
|
2020-09-15 15:10:41 +02:00
|
|
|
Err: Send + 'static,
|
|
|
|
F: FnOnce() -> Result<Response, Err>
|
2020-05-01 14:48:11 +00:00
|
|
|
{
|
|
|
|
let res = create_response();
|
|
|
|
async move { res }.boxed()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "errorlog")]
|
2020-09-15 15:10:41 +02:00
|
|
|
fn errorlog<E: Display>(e: E) {
|
2020-05-01 14:48:11 +00:00
|
|
|
error!("The handler encountered an error: {}", e);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(feature = "errorlog"))]
|
2020-09-15 15:10:41 +02:00
|
|
|
fn errorlog<E>(_e: E) {}
|
2020-05-01 14:48:11 +00:00
|
|
|
|
2020-09-15 15:10:41 +02:00
|
|
|
fn handle_error<E>(e: E) -> Pin<Box<dyn Future<Output = Result<Response, E::Err>> + Send>>
|
2020-05-01 14:48:11 +00:00
|
|
|
where
|
2020-09-15 15:10:41 +02:00
|
|
|
E: Display + IntoResponseError
|
2020-05-01 14:48:11 +00:00
|
|
|
{
|
|
|
|
into_response_helper(|| {
|
|
|
|
errorlog(&e);
|
|
|
|
e.into_response_error()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<Res> ResourceResult for Pin<Box<dyn Future<Output = Res> + Send>>
|
|
|
|
where
|
2020-09-15 15:10:41 +02:00
|
|
|
Res: ResourceResult + 'static
|
2020-05-01 14:48:11 +00:00
|
|
|
{
|
|
|
|
type Err = Res::Err;
|
2020-09-15 15:10:41 +02:00
|
|
|
|
|
|
|
fn into_response(self) -> Pin<Box<dyn Future<Output = Result<Response, Self::Err>> + Send>> {
|
|
|
|
self.then(|result| result.into_response()).boxed()
|
2020-05-01 14:48:11 +00:00
|
|
|
}
|
2020-09-15 15:10:41 +02:00
|
|
|
|
|
|
|
fn accepted_types() -> Option<Vec<Mime>> {
|
2020-05-01 14:48:11 +00:00
|
|
|
Res::accepted_types()
|
|
|
|
}
|
2020-09-15 15:10:41 +02:00
|
|
|
|
2020-05-01 14:48:11 +00:00
|
|
|
#[cfg(feature = "openapi")]
|
2020-09-15 15:10:41 +02:00
|
|
|
fn schema() -> OpenapiSchema {
|
2020-05-01 14:48:11 +00:00
|
|
|
Res::schema()
|
|
|
|
}
|
2020-09-15 15:10:41 +02:00
|
|
|
|
2020-05-01 14:48:11 +00:00
|
|
|
#[cfg(feature = "openapi")]
|
2020-09-15 15:10:41 +02:00
|
|
|
fn default_status() -> crate::StatusCode {
|
2020-05-01 14:48:11 +00:00
|
|
|
Res::default_status()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
2020-09-15 15:10:41 +02:00
|
|
|
mod test {
|
2020-05-01 14:48:11 +00:00
|
|
|
use super::*;
|
|
|
|
use futures_executor::block_on;
|
|
|
|
use thiserror::Error;
|
2020-09-15 15:10:41 +02:00
|
|
|
|
2020-05-01 14:48:11 +00:00
|
|
|
#[derive(Debug, Default, Deserialize, Serialize)]
|
2020-05-03 18:48:55 +02:00
|
|
|
#[cfg_attr(feature = "openapi", derive(crate::OpenapiType))]
|
2020-09-15 15:10:41 +02:00
|
|
|
struct Msg {
|
|
|
|
msg: String
|
2020-05-01 14:48:11 +00:00
|
|
|
}
|
2020-09-15 15:10:41 +02:00
|
|
|
|
2020-05-01 14:48:11 +00:00
|
|
|
#[derive(Debug, Default, Error)]
|
|
|
|
#[error("An Error")]
|
|
|
|
struct MsgError;
|
2020-09-15 15:10:41 +02:00
|
|
|
|
2020-05-01 14:48:11 +00:00
|
|
|
#[test]
|
2020-09-15 15:10:41 +02:00
|
|
|
fn result_from_future() {
|
2020-05-03 18:48:55 +02:00
|
|
|
let nc = NoContent::default();
|
|
|
|
let res = block_on(nc.into_response()).unwrap();
|
2020-09-15 15:10:41 +02:00
|
|
|
|
2020-05-03 18:48:55 +02:00
|
|
|
let fut_nc = async move { NoContent::default() }.boxed();
|
|
|
|
let fut_res = block_on(fut_nc.into_response()).unwrap();
|
2020-09-15 15:10:41 +02:00
|
|
|
|
2020-05-03 18:48:55 +02:00
|
|
|
assert_eq!(res.status, fut_res.status);
|
|
|
|
assert_eq!(res.mime, fut_res.mime);
|
|
|
|
assert_eq!(res.full_body().unwrap(), fut_res.full_body().unwrap());
|
2020-05-01 14:48:11 +00:00
|
|
|
}
|
|
|
|
}
|