2019-10-20 14:49:53 +00:00
|
|
|
use crate::{ResponseBody, StatusCode};
|
2019-10-01 00:23:34 +02:00
|
|
|
#[cfg(feature = "openapi")]
|
2019-10-05 14:50:05 +02:00
|
|
|
use crate::{OpenapiSchema, OpenapiType};
|
2019-10-20 14:49:53 +00:00
|
|
|
use hyper::Body;
|
2020-02-10 21:41:44 +01:00
|
|
|
use log::error;
|
2019-10-20 14:49:53 +00:00
|
|
|
use mime::{Mime, APPLICATION_JSON, STAR_STAR};
|
|
|
|
#[cfg(feature = "openapi")]
|
|
|
|
use openapiv3::{SchemaKind, StringFormat, StringType, Type, VariantOrUnknownOrEmpty};
|
2019-09-26 17:24:40 +02:00
|
|
|
use serde::Serialize;
|
2019-09-27 15:35:02 +02:00
|
|
|
use serde_json::error::Error as SerdeJsonError;
|
2020-01-25 15:59:37 +01:00
|
|
|
use std::{
|
|
|
|
error::Error,
|
|
|
|
fmt::Debug
|
|
|
|
};
|
2019-09-26 17:24:40 +02:00
|
|
|
|
2019-10-20 14:49:53 +00:00
|
|
|
/// A response, used to create the final gotham response from.
|
|
|
|
pub struct Response
|
|
|
|
{
|
|
|
|
pub status : StatusCode,
|
|
|
|
pub body : Body,
|
|
|
|
pub mime : Option<Mime>
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Response
|
|
|
|
{
|
|
|
|
/// Create a new `Response` from raw data.
|
|
|
|
pub fn new<B : Into<Body>>(status : StatusCode, body : B, mime : Option<Mime>) -> Self
|
|
|
|
{
|
|
|
|
Self {
|
|
|
|
status,
|
|
|
|
body: body.into(),
|
|
|
|
mime
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create a `Response` with mime type json from already serialized data.
|
|
|
|
pub fn json<B : Into<Body>>(status : StatusCode, body : B) -> Self
|
|
|
|
{
|
|
|
|
Self {
|
|
|
|
status,
|
|
|
|
body: body.into(),
|
|
|
|
mime: Some(APPLICATION_JSON)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create a _204 No Content_ `Response`.
|
|
|
|
pub fn no_content() -> Self
|
|
|
|
{
|
|
|
|
Self {
|
|
|
|
status: StatusCode::NO_CONTENT,
|
|
|
|
body: Body::empty(),
|
|
|
|
mime: None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-25 15:59:37 +01:00
|
|
|
/// Create an empty _403 Forbidden_ `Response`.
|
|
|
|
pub fn forbidden() -> Self
|
|
|
|
{
|
|
|
|
Self {
|
|
|
|
status: StatusCode::FORBIDDEN,
|
|
|
|
body: Body::empty(),
|
|
|
|
mime: None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-20 14:49:53 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
fn full_body(self) -> Vec<u8>
|
|
|
|
{
|
|
|
|
use futures::{future::Future, stream::Stream};
|
|
|
|
|
|
|
|
let bytes : &[u8] = &self.body.concat2().wait().unwrap().into_bytes();
|
|
|
|
bytes.to_vec()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-27 15:35:02 +02:00
|
|
|
/// A trait provided to convert a resource's result to json.
|
|
|
|
pub trait ResourceResult
|
2019-09-26 17:24:40 +02:00
|
|
|
{
|
2019-10-20 14:49:53 +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) -> Result<Response, SerdeJsonError>;
|
|
|
|
|
|
|
|
/// Return a list of supported mime types.
|
|
|
|
fn accepted_types() -> Option<Vec<Mime>>
|
|
|
|
{
|
|
|
|
None
|
|
|
|
}
|
2019-09-30 23:53:55 +02:00
|
|
|
|
|
|
|
#[cfg(feature = "openapi")]
|
2019-10-13 23:36:10 +02:00
|
|
|
fn schema() -> OpenapiSchema;
|
2019-10-05 14:50:05 +02:00
|
|
|
|
|
|
|
#[cfg(feature = "openapi")]
|
|
|
|
fn default_status() -> StatusCode
|
|
|
|
{
|
|
|
|
StatusCode::OK
|
|
|
|
}
|
2020-02-10 21:17:49 +01:00
|
|
|
|
|
|
|
#[cfg(feature = "openapi")]
|
|
|
|
fn requires_auth() -> bool
|
|
|
|
{
|
|
|
|
false
|
|
|
|
}
|
2019-09-26 17:24:40 +02:00
|
|
|
}
|
|
|
|
|
2019-10-01 00:49:13 +02:00
|
|
|
#[cfg(feature = "openapi")]
|
|
|
|
impl<Res : ResourceResult> crate::OpenapiType for Res
|
|
|
|
{
|
2019-10-13 23:36:10 +02:00
|
|
|
fn schema() -> OpenapiSchema
|
2019-10-01 00:49:13 +02:00
|
|
|
{
|
2019-10-13 23:36:10 +02:00
|
|
|
Self::schema()
|
2019-10-01 00:49:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-27 15:35:02 +02:00
|
|
|
/// The default json returned on an 500 Internal Server Error.
|
2019-09-26 17:24:40 +02:00
|
|
|
#[derive(Debug, Serialize)]
|
|
|
|
pub struct ResourceError
|
|
|
|
{
|
|
|
|
error : bool,
|
|
|
|
message : String
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T : ToString> From<T> for ResourceError
|
|
|
|
{
|
|
|
|
fn from(message : T) -> Self
|
|
|
|
{
|
|
|
|
Self {
|
|
|
|
error: true,
|
|
|
|
message: message.to_string()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-20 14:49:53 +00:00
|
|
|
impl<R : ResponseBody, E : Error> ResourceResult for Result<R, E>
|
2019-09-26 17:24:40 +02:00
|
|
|
{
|
2019-10-20 14:49:53 +00:00
|
|
|
fn into_response(self) -> Result<Response, SerdeJsonError>
|
2019-09-26 17:24:40 +02:00
|
|
|
{
|
2019-09-27 15:35:02 +02:00
|
|
|
Ok(match self {
|
2019-10-20 14:49:53 +00:00
|
|
|
Ok(r) => Response::json(StatusCode::OK, serde_json::to_string(&r)?),
|
2019-09-27 15:35:02 +02:00
|
|
|
Err(e) => {
|
2020-02-10 21:41:44 +01:00
|
|
|
if cfg!(feature = "errorlog")
|
|
|
|
{
|
|
|
|
error!("The handler encountered an error: {}", e);
|
|
|
|
}
|
2019-09-27 15:35:02 +02:00
|
|
|
let err : ResourceError = e.into();
|
2019-10-20 14:49:53 +00:00
|
|
|
Response::json(StatusCode::INTERNAL_SERVER_ERROR, serde_json::to_string(&err)?)
|
2019-09-27 15:35:02 +02:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2019-09-30 23:53:55 +02:00
|
|
|
|
2019-10-20 14:49:53 +00:00
|
|
|
fn accepted_types() -> Option<Vec<Mime>>
|
|
|
|
{
|
|
|
|
Some(vec![APPLICATION_JSON])
|
|
|
|
}
|
|
|
|
|
2019-09-30 23:53:55 +02:00
|
|
|
#[cfg(feature = "openapi")]
|
2019-10-13 23:36:10 +02:00
|
|
|
fn schema() -> OpenapiSchema
|
2019-09-30 20:58:15 +02:00
|
|
|
{
|
2019-10-13 23:36:10 +02:00
|
|
|
R::schema()
|
2019-09-30 20:58:15 +02:00
|
|
|
}
|
2019-09-27 15:35:02 +02:00
|
|
|
}
|
|
|
|
|
2019-10-14 00:59:02 +02:00
|
|
|
/**
|
|
|
|
This can be returned from a resource when there is no cause of an error. For example:
|
|
|
|
|
|
|
|
```
|
|
|
|
# #[macro_use] extern crate gotham_restful_derive;
|
|
|
|
# use gotham::state::State;
|
2019-10-14 02:37:50 +02:00
|
|
|
# use gotham_restful::*;
|
2019-10-14 00:59:02 +02:00
|
|
|
# use serde::{Deserialize, Serialize};
|
|
|
|
#
|
|
|
|
# #[derive(Resource)]
|
|
|
|
# struct MyResource;
|
|
|
|
#
|
|
|
|
#[derive(Deserialize, Serialize)]
|
|
|
|
# #[derive(OpenapiType)]
|
|
|
|
struct MyResponse {
|
|
|
|
message: String
|
|
|
|
}
|
|
|
|
|
|
|
|
#[rest_read_all(MyResource)]
|
|
|
|
fn read_all(_state: &mut State) -> Success<MyResponse> {
|
|
|
|
let res = MyResponse { message: "I'm always happy".to_string() };
|
|
|
|
res.into()
|
|
|
|
}
|
|
|
|
```
|
|
|
|
*/
|
2019-09-27 15:35:02 +02:00
|
|
|
pub struct Success<T>(T);
|
|
|
|
|
|
|
|
impl<T> From<T> for Success<T>
|
|
|
|
{
|
|
|
|
fn from(t : T) -> Self
|
|
|
|
{
|
|
|
|
Self(t)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-25 15:59:37 +01:00
|
|
|
impl<T : Clone> Clone for Success<T>
|
|
|
|
{
|
|
|
|
fn clone(&self) -> Self
|
|
|
|
{
|
|
|
|
Self(self.0.clone())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T : Debug> Debug for Success<T>
|
|
|
|
{
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
write!(f, "Success({:?})", self.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-20 14:49:53 +00:00
|
|
|
impl<T : ResponseBody> ResourceResult for Success<T>
|
2019-09-27 15:35:02 +02:00
|
|
|
{
|
2019-10-20 14:49:53 +00:00
|
|
|
fn into_response(self) -> Result<Response, SerdeJsonError>
|
2019-09-27 15:35:02 +02:00
|
|
|
{
|
2019-10-20 14:49:53 +00:00
|
|
|
Ok(Response::json(StatusCode::OK, serde_json::to_string(&self.0)?))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn accepted_types() -> Option<Vec<Mime>>
|
|
|
|
{
|
|
|
|
Some(vec![APPLICATION_JSON])
|
2019-09-26 17:24:40 +02:00
|
|
|
}
|
2019-09-30 23:53:55 +02:00
|
|
|
|
|
|
|
#[cfg(feature = "openapi")]
|
2019-10-13 23:36:10 +02:00
|
|
|
fn schema() -> OpenapiSchema
|
2019-09-30 20:58:15 +02:00
|
|
|
{
|
2019-10-13 23:36:10 +02:00
|
|
|
T::schema()
|
2019-09-30 20:58:15 +02:00
|
|
|
}
|
2019-09-26 17:24:40 +02:00
|
|
|
}
|
2019-10-05 14:50:05 +02:00
|
|
|
|
2020-01-25 15:59:37 +01:00
|
|
|
/**
|
|
|
|
This return type can be used to map another `ResourceResult` that can only be returned if the
|
|
|
|
client is authenticated. Otherwise, an empty _403 Forbidden_ response will be issued. Use can
|
|
|
|
look something like this (assuming the `auth` feature is enabled):
|
|
|
|
|
|
|
|
```
|
|
|
|
# #[macro_use] extern crate gotham_restful_derive;
|
|
|
|
# use gotham::state::State;
|
|
|
|
# use gotham_restful::*;
|
|
|
|
# use serde::Deserialize;
|
|
|
|
#
|
|
|
|
# #[derive(Resource)]
|
|
|
|
# struct MyResource;
|
|
|
|
#
|
|
|
|
# #[derive(Clone, Deserialize)]
|
|
|
|
# struct MyAuthData { exp : u64 }
|
|
|
|
#
|
|
|
|
#[rest_read_all(MyResource)]
|
|
|
|
fn read_all(auth : AuthStatus<MyAuthData>) -> AuthResult<NoContent> {
|
|
|
|
let auth_data = match auth {
|
|
|
|
AuthStatus::Authenticated(data) => data,
|
|
|
|
_ => return AuthErr
|
|
|
|
};
|
|
|
|
// do something
|
|
|
|
NoContent::default().into()
|
|
|
|
}
|
|
|
|
```
|
|
|
|
*/
|
|
|
|
pub enum AuthResult<T>
|
|
|
|
{
|
|
|
|
Ok(T),
|
|
|
|
AuthErr
|
|
|
|
}
|
|
|
|
|
2020-02-08 13:44:46 +01:00
|
|
|
impl<T> AuthResult<T>
|
|
|
|
{
|
|
|
|
pub fn is_ok(&self) -> bool
|
|
|
|
{
|
|
|
|
match self {
|
|
|
|
Self::Ok(_) => true,
|
|
|
|
_ => false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn unwrap(self) -> T
|
|
|
|
{
|
|
|
|
match self {
|
|
|
|
Self::Ok(data) => data,
|
|
|
|
_ => panic!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-25 15:59:37 +01:00
|
|
|
impl<T> From<T> for AuthResult<T>
|
|
|
|
{
|
|
|
|
fn from(t : T) -> Self
|
|
|
|
{
|
|
|
|
Self::Ok(t)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T : Clone> Clone for AuthResult<T>
|
|
|
|
{
|
|
|
|
fn clone(&self) -> Self
|
|
|
|
{
|
|
|
|
match self {
|
|
|
|
Self::Ok(t) => Self::Ok(t.clone()),
|
|
|
|
Self::AuthErr => Self::AuthErr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T : Debug> Debug for AuthResult<T>
|
|
|
|
{
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
match self {
|
|
|
|
Self::Ok(t) => write!(f, "Ok({:?})", t),
|
|
|
|
Self::AuthErr => write!(f, "AuthErr")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T : ResourceResult> ResourceResult for AuthResult<T>
|
|
|
|
{
|
|
|
|
fn into_response(self) -> Result<Response, SerdeJsonError>
|
|
|
|
{
|
|
|
|
match self
|
|
|
|
{
|
|
|
|
Self::Ok(res) => res.into_response(),
|
|
|
|
Self::AuthErr => Ok(Response::forbidden())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn accepted_types() -> Option<Vec<Mime>>
|
|
|
|
{
|
|
|
|
T::accepted_types()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "openapi")]
|
|
|
|
fn schema() -> OpenapiSchema
|
|
|
|
{
|
|
|
|
T::schema()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "openapi")]
|
|
|
|
fn default_status() -> StatusCode
|
|
|
|
{
|
|
|
|
T::default_status()
|
|
|
|
}
|
2020-02-10 21:17:49 +01:00
|
|
|
|
|
|
|
#[cfg(feature = "openapi")]
|
|
|
|
fn requires_auth() -> bool
|
|
|
|
{
|
|
|
|
true
|
|
|
|
}
|
2020-01-25 15:59:37 +01:00
|
|
|
}
|
|
|
|
|
2019-10-14 00:59:02 +02:00
|
|
|
/**
|
|
|
|
This is the return type of a resource that doesn't actually return something. It will result
|
|
|
|
in a _204 No Content_ answer by default. You don't need to use this type directly if using
|
|
|
|
the function attributes:
|
|
|
|
|
|
|
|
```
|
|
|
|
# #[macro_use] extern crate gotham_restful_derive;
|
|
|
|
# use gotham::state::State;
|
2019-10-14 02:37:50 +02:00
|
|
|
# use gotham_restful::*;
|
2019-10-14 00:59:02 +02:00
|
|
|
#
|
|
|
|
# #[derive(Resource)]
|
|
|
|
# struct MyResource;
|
|
|
|
#
|
|
|
|
#[rest_read_all(MyResource)]
|
|
|
|
fn read_all(_state: &mut State) {
|
|
|
|
// do something
|
|
|
|
}
|
|
|
|
```
|
|
|
|
*/
|
2019-10-13 23:36:10 +02:00
|
|
|
#[derive(Default)]
|
2019-10-05 14:50:05 +02:00
|
|
|
pub struct NoContent;
|
|
|
|
|
|
|
|
impl From<()> for NoContent
|
|
|
|
{
|
|
|
|
fn from(_ : ()) -> Self
|
|
|
|
{
|
|
|
|
Self {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ResourceResult for NoContent
|
|
|
|
{
|
2019-10-14 00:59:02 +02:00
|
|
|
/// This will always be a _204 No Content_ together with an empty string.
|
2019-10-20 14:49:53 +00:00
|
|
|
fn into_response(self) -> Result<Response, SerdeJsonError>
|
2019-10-05 14:50:05 +02:00
|
|
|
{
|
2019-10-20 14:49:53 +00:00
|
|
|
Ok(Response::no_content())
|
2019-10-05 14:50:05 +02:00
|
|
|
}
|
|
|
|
|
2019-10-14 00:59:02 +02:00
|
|
|
/// Returns the schema of the `()` type.
|
2019-10-05 14:50:05 +02:00
|
|
|
#[cfg(feature = "openapi")]
|
2019-10-13 23:36:10 +02:00
|
|
|
fn schema() -> OpenapiSchema
|
2019-10-05 14:50:05 +02:00
|
|
|
{
|
2019-10-13 23:36:10 +02:00
|
|
|
<()>::schema()
|
2019-10-05 14:50:05 +02:00
|
|
|
}
|
|
|
|
|
2019-10-14 00:59:02 +02:00
|
|
|
/// This will always be a _204 No Content_
|
2019-10-05 14:50:05 +02:00
|
|
|
#[cfg(feature = "openapi")]
|
|
|
|
fn default_status() -> StatusCode
|
|
|
|
{
|
|
|
|
StatusCode::NO_CONTENT
|
|
|
|
}
|
|
|
|
}
|
2019-10-05 16:06:08 +02:00
|
|
|
|
|
|
|
impl<E : Error> ResourceResult for Result<NoContent, E>
|
|
|
|
{
|
2019-10-20 14:49:53 +00:00
|
|
|
fn into_response(self) -> Result<Response, SerdeJsonError>
|
2019-10-05 16:06:08 +02:00
|
|
|
{
|
2019-10-20 14:49:53 +00:00
|
|
|
match self {
|
|
|
|
Ok(nc) => nc.into_response(),
|
2019-10-05 16:06:08 +02:00
|
|
|
Err(e) => {
|
|
|
|
let err : ResourceError = e.into();
|
2019-10-20 14:49:53 +00:00
|
|
|
Ok(Response::json(StatusCode::INTERNAL_SERVER_ERROR, serde_json::to_string(&err)?))
|
2019-10-05 16:06:08 +02:00
|
|
|
}
|
2019-10-20 14:49:53 +00:00
|
|
|
}
|
2019-10-05 16:06:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "openapi")]
|
2019-10-13 23:36:10 +02:00
|
|
|
fn schema() -> OpenapiSchema
|
2019-10-05 16:06:08 +02:00
|
|
|
{
|
2019-10-14 02:17:25 +02:00
|
|
|
<NoContent as ResourceResult>::schema()
|
2019-10-05 16:06:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "openapi")]
|
|
|
|
fn default_status() -> StatusCode
|
|
|
|
{
|
2019-10-14 02:17:25 +02:00
|
|
|
NoContent::default_status()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-20 14:49:53 +00:00
|
|
|
pub struct Raw<T>
|
|
|
|
{
|
|
|
|
pub raw : T,
|
|
|
|
pub mime : Mime
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> Raw<T>
|
|
|
|
{
|
|
|
|
pub fn new(raw : T, mime : Mime) -> Self
|
|
|
|
{
|
|
|
|
Self { raw, mime }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-25 15:59:37 +01:00
|
|
|
impl<T : Clone> Clone for Raw<T>
|
|
|
|
{
|
|
|
|
fn clone(&self) -> Self
|
|
|
|
{
|
|
|
|
Self {
|
|
|
|
raw: self.raw.clone(),
|
|
|
|
mime: self.mime.clone()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T : Debug> Debug for Raw<T>
|
|
|
|
{
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
write!(f, "Raw({:?}, {:?})", self.raw, self.mime)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-20 14:49:53 +00:00
|
|
|
impl<T : Into<Body>> ResourceResult for Raw<T>
|
|
|
|
{
|
|
|
|
fn into_response(self) -> Result<Response, SerdeJsonError>
|
|
|
|
{
|
|
|
|
Ok(Response::new(StatusCode::OK, self.raw, Some(self.mime.clone())))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn accepted_types() -> Option<Vec<Mime>>
|
|
|
|
{
|
|
|
|
Some(vec![STAR_STAR])
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "openapi")]
|
|
|
|
fn schema() -> OpenapiSchema
|
|
|
|
{
|
|
|
|
OpenapiSchema::new(SchemaKind::Type(Type::String(StringType {
|
|
|
|
format: VariantOrUnknownOrEmpty::Item(StringFormat::Binary),
|
2020-01-17 21:37:41 +01:00
|
|
|
..Default::default()
|
2019-10-20 14:49:53 +00:00
|
|
|
})))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T, E : Error> ResourceResult for Result<Raw<T>, E>
|
|
|
|
where
|
|
|
|
Raw<T> : ResourceResult
|
|
|
|
{
|
|
|
|
fn into_response(self) -> Result<Response, SerdeJsonError>
|
|
|
|
{
|
|
|
|
match self {
|
|
|
|
Ok(raw) => raw.into_response(),
|
|
|
|
Err(e) => {
|
|
|
|
let err : ResourceError = e.into();
|
|
|
|
Ok(Response::json(StatusCode::INTERNAL_SERVER_ERROR, serde_json::to_string(&err)?))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn accepted_types() -> Option<Vec<Mime>>
|
|
|
|
{
|
|
|
|
<Raw<T> as ResourceResult>::accepted_types()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "openapi")]
|
|
|
|
fn schema() -> OpenapiSchema
|
|
|
|
{
|
|
|
|
<Raw<T> as ResourceResult>::schema()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-10-14 02:17:25 +02:00
|
|
|
#[cfg(test)]
|
|
|
|
mod test
|
|
|
|
{
|
|
|
|
use super::*;
|
2019-10-20 14:49:53 +00:00
|
|
|
use mime::TEXT_PLAIN;
|
2019-10-14 02:17:25 +02:00
|
|
|
use thiserror::Error;
|
|
|
|
|
|
|
|
#[derive(Debug, Default, Deserialize, Serialize)]
|
|
|
|
#[cfg_attr(feature = "openapi", derive(OpenapiType))]
|
|
|
|
struct Msg
|
|
|
|
{
|
|
|
|
msg : String
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Default, Error)]
|
|
|
|
#[error("An Error")]
|
|
|
|
struct MsgError;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn resource_result_ok()
|
|
|
|
{
|
|
|
|
let ok : Result<Msg, MsgError> = Ok(Msg::default());
|
2019-10-20 14:49:53 +00:00
|
|
|
let res = ok.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(), r#"{"msg":""}"#.as_bytes());
|
2019-10-14 02:17:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn resource_result_err()
|
|
|
|
{
|
|
|
|
let err : Result<Msg, MsgError> = Err(MsgError::default());
|
2019-10-20 14:49:53 +00:00
|
|
|
let res = err.into_response().expect("didn't expect error response");
|
|
|
|
assert_eq!(res.status, StatusCode::INTERNAL_SERVER_ERROR);
|
|
|
|
assert_eq!(res.mime, Some(APPLICATION_JSON));
|
|
|
|
assert_eq!(res.full_body(), format!(r#"{{"error":true,"message":"{}"}}"#, MsgError::default()).as_bytes());
|
2019-10-14 02:17:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn success_always_successfull()
|
|
|
|
{
|
|
|
|
let success : Success<Msg> = Msg::default().into();
|
2019-10-20 14:49:53 +00:00
|
|
|
let res = 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(), r#"{"msg":""}"#.as_bytes());
|
2019-10-14 02:17:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2019-10-20 14:49:53 +00:00
|
|
|
fn no_content_has_empty_response()
|
2019-10-14 02:17:25 +02:00
|
|
|
{
|
|
|
|
let no_content = NoContent::default();
|
2019-10-20 14:49:53 +00:00
|
|
|
let res = no_content.into_response().expect("didn't expect error response");
|
|
|
|
assert_eq!(res.status, StatusCode::NO_CONTENT);
|
|
|
|
assert_eq!(res.mime, None);
|
|
|
|
assert_eq!(res.full_body(), &[] as &[u8]);
|
2019-10-14 02:17:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn no_content_result()
|
|
|
|
{
|
2019-10-20 14:49:53 +00:00
|
|
|
let no_content : Result<NoContent, MsgError> = Ok(NoContent::default());
|
|
|
|
let res = no_content.into_response().expect("didn't expect error response");
|
|
|
|
assert_eq!(res.status, StatusCode::NO_CONTENT);
|
|
|
|
assert_eq!(res.mime, None);
|
|
|
|
assert_eq!(res.full_body(), &[] as &[u8]);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn raw_response()
|
|
|
|
{
|
|
|
|
let msg = "Test";
|
|
|
|
let raw = Raw::new(msg, TEXT_PLAIN);
|
|
|
|
let res = raw.into_response().expect("didn't expect error response");
|
|
|
|
assert_eq!(res.status, StatusCode::OK);
|
|
|
|
assert_eq!(res.mime, Some(TEXT_PLAIN));
|
|
|
|
assert_eq!(res.full_body(), msg.as_bytes());
|
2019-10-05 16:06:08 +02:00
|
|
|
}
|
|
|
|
}
|