gotham_restful/response/
auth_result.rs

1use crate::{IntoResponseError, Response};
2use gotham::{hyper::StatusCode, mime::TEXT_PLAIN_UTF_8};
3use gotham_restful_derive::ResourceError;
4#[cfg(feature = "openapi")]
5use openapi_type::{OpenapiSchema, OpenapiType};
6
7/// This is an error type that always yields a _403 Forbidden_ response. This type
8/// is best used in combination with [`AuthSuccess`] or [`AuthResult`].
9#[derive(Clone, Debug)]
10pub struct AuthError(String);
11
12impl AuthError {
13	pub fn new<T: Into<String>>(msg: T) -> Self {
14		Self(msg.into())
15	}
16}
17
18impl IntoResponseError for AuthError {
19	// TODO why does this need to be serde_json::Error ?!?
20	type Err = serde_json::Error;
21
22	fn into_response_error(self) -> Result<Response, Self::Err> {
23		Ok(Response::new(
24			StatusCode::FORBIDDEN,
25			self.0,
26			Some(TEXT_PLAIN_UTF_8)
27		))
28	}
29
30	#[cfg(feature = "openapi")]
31	fn status_codes() -> Vec<StatusCode> {
32		vec![StatusCode::FORBIDDEN]
33	}
34
35	#[cfg(feature = "openapi")]
36	fn schema(code: StatusCode) -> OpenapiSchema {
37		assert_eq!(code, StatusCode::FORBIDDEN);
38		<super::Raw<String> as OpenapiType>::schema()
39	}
40}
41
42/// This return type can be used to wrap any type implementing [IntoResponse](crate::IntoResponse)
43/// that can only be returned if the client is authenticated. Otherwise, an empty _403 Forbidden_
44/// response will be issued.
45///
46/// Use can look something like this (assuming the `auth` feature is enabled):
47///
48/// ```rust
49/// # #[macro_use] extern crate gotham_restful_derive;
50/// # #[cfg(feature = "auth")]
51/// # mod auth_feature_enabled {
52/// # use gotham::state::State;
53/// # use gotham_restful::*;
54/// # use serde::Deserialize;
55/// #
56/// # #[derive(Resource)]
57/// # #[resource(read_all)]
58/// # struct MyResource;
59/// #
60/// # #[derive(Clone, Deserialize)]
61/// # struct MyAuthData { exp : u64 }
62/// #
63/// #[read_all]
64/// fn read_all(auth: AuthStatus<MyAuthData>) -> AuthSuccess<NoContent> {
65/// 	let auth_data = auth.ok()?;
66/// 	// do something
67/// 	Ok(NoContent::default())
68/// }
69/// # }
70/// ```
71pub type AuthSuccess<T> = Result<T, AuthError>;
72
73/// This is an error type that either yields a _403 Forbidden_ response if produced
74/// from an authentication error, or delegates to another error type. This type is
75/// best used with [`AuthResult`].
76#[derive(Debug, Clone, ResourceError)]
77pub enum AuthErrorOrOther<E> {
78	Forbidden(#[from] AuthError),
79
80	#[status(INTERNAL_SERVER_ERROR)]
81	#[display("{0}")]
82	Other(E)
83}
84
85mod private {
86	use gotham::handler::HandlerError;
87	pub trait Sealed {}
88	impl<E: Into<HandlerError>> Sealed for E {}
89}
90
91impl<E, F> From<F> for AuthErrorOrOther<E>
92where
93	// TODO https://github.com/msrd0/gotham_restful/issues/20
94	F: private::Sealed + Into<E>
95{
96	fn from(err: F) -> Self {
97		Self::Other(err.into())
98	}
99}
100
101/// This return type can be used to wrap any type implementing [IntoResponse](crate::IntoResponse)
102/// that can only be returned if the client is authenticated. Otherwise, an empty _403 Forbidden_
103/// response will be issued.
104///
105/// Use can look something like this (assuming the `auth` feature is enabled):
106///
107/// ```
108/// # #[macro_use] extern crate gotham_restful_derive;
109/// # #[cfg(feature = "auth")]
110/// # mod auth_feature_enabled {
111/// # use gotham::state::State;
112/// # use gotham_restful::*;
113/// # use serde::Deserialize;
114/// # use std::io;
115/// #
116/// # #[derive(Resource)]
117/// # #[resource(read_all)]
118/// # struct MyResource;
119/// #
120/// # #[derive(Clone, Deserialize)]
121/// # struct MyAuthData { exp : u64 }
122/// #
123/// #[read_all]
124/// fn read_all(auth: AuthStatus<MyAuthData>) -> AuthResult<NoContent, io::Error> {
125/// 	let auth_data = auth.ok()?;
126/// 	// do something
127/// 	Ok(NoContent::default().into())
128/// }
129/// # }
130/// ```
131pub type AuthResult<T, E> = Result<T, AuthErrorOrOther<E>>;