mirror of
https://gitlab.com/msrd0/gotham-restful.git
synced 2025-02-22 20:52:27 +00:00
split the ResourceResult trait
This commit is contained in:
parent
c640efcb88
commit
7de11cdae1
12 changed files with 102 additions and 29 deletions
|
@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- All fields of `Response` are now private
|
||||
- If not enabling the `openapi` feature, `without-openapi` has to be enabled
|
||||
- The endpoint macro attributes (`read`, `create`, ...) no longer take the resource ident and reject all unknown attributes ([!18])
|
||||
- The `ResourceResult` trait has been split into `ResourceResult` and `ResourceResultSchema`
|
||||
|
||||
### Removed
|
||||
- All pre-defined methods (`read`, `create`, ...) from our router extensions ([!18])
|
||||
|
|
|
@ -16,6 +16,7 @@ pub trait Endpoint {
|
|||
fn uri() -> Cow<'static, str>;
|
||||
|
||||
/// The output type that provides the response.
|
||||
#[openapi_bound("Output: crate::ResourceResultSchema")]
|
||||
type Output: ResourceResult + Send;
|
||||
|
||||
/// Returns `true` _iff_ the URI contains placeholders. `false` by default.
|
||||
|
|
|
@ -482,6 +482,8 @@ pub use result::{
|
|||
AuthError, AuthError::Forbidden, AuthErrorOrOther, AuthResult, AuthSuccess, IntoResponseError, NoContent, Raw, Redirect,
|
||||
ResourceResult, Success
|
||||
};
|
||||
#[cfg(feature = "openapi")]
|
||||
pub use result::{ResourceResultSchema, ResourceResultWithSchema};
|
||||
|
||||
mod routing;
|
||||
pub use routing::{DrawResourceRoutes, DrawResources};
|
||||
|
|
|
@ -188,7 +188,7 @@ mod test {
|
|||
#[test]
|
||||
fn no_content_schema_to_content() {
|
||||
let types = NoContent::accepted_types();
|
||||
let schema = <NoContent as ResourceResult>::schema();
|
||||
let schema = <NoContent as ResourceResultSchema>::schema();
|
||||
let content = OperationDescription::schema_to_content(types.or_all_types(), Item(schema.into_schema()));
|
||||
assert!(content.is_empty());
|
||||
}
|
||||
|
@ -196,7 +196,7 @@ mod test {
|
|||
#[test]
|
||||
fn raw_schema_to_content() {
|
||||
let types = Raw::<&str>::accepted_types();
|
||||
let schema = <Raw<&str> as ResourceResult>::schema();
|
||||
let schema = <Raw<&str> as ResourceResultSchema>::schema();
|
||||
let content = OperationDescription::schema_to_content(types.or_all_types(), Item(schema.into_schema()));
|
||||
assert_eq!(content.len(), 1);
|
||||
let json = serde_json::to_string(&content.values().nth(0).unwrap()).unwrap();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use super::{builder::OpenapiBuilder, handler::OpenapiHandler, operation::OperationDescription};
|
||||
use crate::{routing::*, EndpointWithSchema, OpenapiType, ResourceResult, ResourceWithSchema};
|
||||
use crate::{routing::*, EndpointWithSchema, OpenapiType, ResourceResultSchema, ResourceWithSchema};
|
||||
use gotham::{hyper::Method, pipeline::chain::PipelineHandleChain, router::builder::*};
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::{Captures, Regex};
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
use crate::OpenapiSchema;
|
||||
use crate::Response;
|
||||
|
||||
use futures_util::future::FutureExt;
|
||||
use futures_util::future::{BoxFuture, FutureExt};
|
||||
use gotham::handler::HandlerError;
|
||||
#[cfg(feature = "openapi")]
|
||||
use gotham::hyper::StatusCode;
|
||||
|
@ -49,22 +49,41 @@ pub trait ResourceResult {
|
|||
|
||||
/// 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>>;
|
||||
fn into_response(self) -> BoxFuture<'static, Result<Response, Self::Err>>;
|
||||
|
||||
/// Return a list of supported mime types.
|
||||
fn accepted_types() -> Option<Vec<Mime>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "openapi")]
|
||||
/// Additional details for [ResourceResult] to be used with an OpenAPI-aware router.
|
||||
#[cfg(feature = "openapi")]
|
||||
pub trait ResourceResultSchema {
|
||||
fn schema() -> OpenapiSchema;
|
||||
|
||||
#[cfg(feature = "openapi")]
|
||||
fn default_status() -> StatusCode {
|
||||
StatusCode::OK
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "openapi")]
|
||||
mod private {
|
||||
pub trait Sealed {}
|
||||
}
|
||||
|
||||
/// A trait provided to convert a resource's result to json, and provide an OpenAPI schema to the
|
||||
/// router. This trait is implemented for all types that implement [ResourceResult] and
|
||||
/// [ResourceResultSchema].
|
||||
#[cfg(feature = "openapi")]
|
||||
pub trait ResourceResultWithSchema: ResourceResult + ResourceResultSchema + private::Sealed {}
|
||||
|
||||
#[cfg(feature = "openapi")]
|
||||
impl<R: ResourceResult + ResourceResultSchema> private::Sealed for R {}
|
||||
|
||||
#[cfg(feature = "openapi")]
|
||||
impl<R: ResourceResult + ResourceResultSchema> ResourceResultWithSchema for R {}
|
||||
|
||||
/// The default json returned on an 500 Internal Server Error.
|
||||
#[derive(Debug, Serialize)]
|
||||
pub(crate) struct ResourceError {
|
||||
|
@ -130,8 +149,13 @@ where
|
|||
fn accepted_types() -> Option<Vec<Mime>> {
|
||||
Res::accepted_types()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "openapi")]
|
||||
#[cfg(feature = "openapi")]
|
||||
impl<Res> ResourceResultSchema for Pin<Box<dyn Future<Output = Res> + Send>>
|
||||
where
|
||||
Res: ResourceResultSchema
|
||||
{
|
||||
fn schema() -> OpenapiSchema {
|
||||
Res::schema()
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::{handle_error, ResourceResult};
|
||||
use crate::{IntoResponseError, Response};
|
||||
#[cfg(feature = "openapi")]
|
||||
use crate::{OpenapiSchema, OpenapiType};
|
||||
use crate::{OpenapiSchema, OpenapiType, ResourceResultSchema};
|
||||
|
||||
use futures_util::{future, future::FutureExt};
|
||||
#[cfg(feature = "openapi")]
|
||||
|
@ -52,15 +52,16 @@ impl ResourceResult for NoContent {
|
|||
fn accepted_types() -> Option<Vec<Mime>> {
|
||||
Some(Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "openapi")]
|
||||
impl ResourceResultSchema for NoContent {
|
||||
/// Returns the schema of the `()` type.
|
||||
#[cfg(feature = "openapi")]
|
||||
fn schema() -> OpenapiSchema {
|
||||
<()>::schema()
|
||||
}
|
||||
|
||||
/// This will always be a _204 No Content_
|
||||
#[cfg(feature = "openapi")]
|
||||
fn default_status() -> StatusCode {
|
||||
StatusCode::NO_CONTENT
|
||||
}
|
||||
|
@ -82,10 +83,15 @@ where
|
|||
fn accepted_types() -> Option<Vec<Mime>> {
|
||||
NoContent::accepted_types()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "openapi")]
|
||||
#[cfg(feature = "openapi")]
|
||||
impl<E> ResourceResultSchema for Result<NoContent, E>
|
||||
where
|
||||
E: Display + IntoResponseError<Err = serde_json::Error>
|
||||
{
|
||||
fn schema() -> OpenapiSchema {
|
||||
<NoContent as ResourceResult>::schema()
|
||||
<NoContent as ResourceResultSchema>::schema()
|
||||
}
|
||||
|
||||
#[cfg(feature = "openapi")]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::{handle_error, IntoResponseError, ResourceResult};
|
||||
use crate::{FromBody, RequestBody, ResourceType, Response};
|
||||
#[cfg(feature = "openapi")]
|
||||
use crate::{OpenapiSchema, OpenapiType};
|
||||
use crate::{OpenapiSchema, OpenapiType, ResourceResultSchema};
|
||||
|
||||
use futures_core::future::Future;
|
||||
use futures_util::{future, future::FutureExt};
|
||||
|
@ -108,8 +108,13 @@ where
|
|||
fn into_response(self) -> Pin<Box<dyn Future<Output = Result<Response, SerdeJsonError>> + Send>> {
|
||||
future::ok(Response::new(StatusCode::OK, self.raw, Some(self.mime))).boxed()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "openapi")]
|
||||
#[cfg(feature = "openapi")]
|
||||
impl<T: Into<Body>> ResourceResultSchema for Raw<T>
|
||||
where
|
||||
Self: Send
|
||||
{
|
||||
fn schema() -> OpenapiSchema {
|
||||
<Self as OpenapiType>::schema()
|
||||
}
|
||||
|
@ -128,10 +133,16 @@ where
|
|||
Err(e) => handle_error(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "openapi")]
|
||||
#[cfg(feature = "openapi")]
|
||||
impl<T, E> ResourceResultSchema for Result<Raw<T>, E>
|
||||
where
|
||||
Raw<T>: ResourceResult + ResourceResultSchema,
|
||||
E: Display + IntoResponseError<Err = <Raw<T> as ResourceResult>::Err>
|
||||
{
|
||||
fn schema() -> OpenapiSchema {
|
||||
<Raw<T> as ResourceResult>::schema()
|
||||
<Raw<T> as ResourceResultSchema>::schema()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::{handle_error, ResourceResult};
|
||||
use crate::{IntoResponseError, Response};
|
||||
#[cfg(feature = "openapi")]
|
||||
use crate::{NoContent, OpenapiSchema};
|
||||
use crate::{NoContent, OpenapiSchema, ResourceResultSchema};
|
||||
use futures_util::future::{BoxFuture, FutureExt, TryFutureExt};
|
||||
use gotham::hyper::{
|
||||
header::{InvalidHeaderValue, LOCATION},
|
||||
|
@ -53,15 +53,16 @@ impl ResourceResult for Redirect {
|
|||
}
|
||||
.boxed()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "openapi")]
|
||||
#[cfg(feature = "openapi")]
|
||||
impl ResourceResultSchema for Redirect {
|
||||
fn default_status() -> StatusCode {
|
||||
StatusCode::SEE_OTHER
|
||||
}
|
||||
|
||||
#[cfg(feature = "openapi")]
|
||||
fn schema() -> OpenapiSchema {
|
||||
<NoContent as ResourceResult>::schema()
|
||||
<NoContent as ResourceResultSchema>::schema()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,15 +89,20 @@ where
|
|||
Err(e) => handle_error(e).map_err(|e| RedirectError::Other(e)).boxed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "openapi")]
|
||||
#[cfg(feature = "openapi")]
|
||||
impl<E> ResourceResultSchema for Result<Redirect, E>
|
||||
where
|
||||
E: Display + IntoResponseError,
|
||||
<E as IntoResponseError>::Err: StdError + Sync
|
||||
{
|
||||
fn default_status() -> StatusCode {
|
||||
Redirect::default_status()
|
||||
}
|
||||
|
||||
#[cfg(feature = "openapi")]
|
||||
fn schema() -> OpenapiSchema {
|
||||
<Redirect as ResourceResult>::schema()
|
||||
<Redirect as ResourceResultSchema>::schema()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::{handle_error, into_response_helper, ResourceResult};
|
||||
#[cfg(feature = "openapi")]
|
||||
use crate::OpenapiSchema;
|
||||
use crate::{result::ResourceError, Response, ResponseBody};
|
||||
#[cfg(feature = "openapi")]
|
||||
use crate::{OpenapiSchema, ResourceResultSchema};
|
||||
|
||||
use futures_core::future::Future;
|
||||
use gotham::hyper::StatusCode;
|
||||
|
@ -43,8 +43,14 @@ where
|
|||
fn accepted_types() -> Option<Vec<Mime>> {
|
||||
Some(vec![APPLICATION_JSON])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "openapi")]
|
||||
#[cfg(feature = "openapi")]
|
||||
impl<R, E> ResourceResultSchema for Result<R, E>
|
||||
where
|
||||
R: ResponseBody,
|
||||
E: Display + IntoResponseError<Err = serde_json::Error>
|
||||
{
|
||||
fn schema() -> OpenapiSchema {
|
||||
R::schema()
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use super::{into_response_helper, ResourceResult};
|
||||
#[cfg(feature = "openapi")]
|
||||
use crate::OpenapiSchema;
|
||||
use crate::{OpenapiSchema, ResourceResultSchema};
|
||||
use crate::{Response, ResponseBody};
|
||||
use gotham::hyper::StatusCode;
|
||||
use mime::{Mime, APPLICATION_JSON};
|
||||
|
@ -104,8 +104,13 @@ where
|
|||
fn accepted_types() -> Option<Vec<Mime>> {
|
||||
Some(vec![APPLICATION_JSON])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "openapi")]
|
||||
#[cfg(feature = "openapi")]
|
||||
impl<T: ResponseBody> ResourceResultSchema for Success<T>
|
||||
where
|
||||
Self: Send
|
||||
{
|
||||
fn schema() -> OpenapiSchema {
|
||||
T::schema()
|
||||
}
|
||||
|
|
|
@ -1,3 +1,14 @@
|
|||
error[E0277]: the trait bound `FooResponse: ResourceResultSchema` is not satisfied
|
||||
--> $DIR/invalid_return_type.rs:12:18
|
||||
|
|
||||
12 | fn endpoint() -> FooResponse {
|
||||
| ^^^^^^^^^^^ the trait `ResourceResultSchema` is not implemented for `FooResponse`
|
||||
|
|
||||
::: $WORKSPACE/src/endpoint.rs
|
||||
|
|
||||
| #[openapi_bound("Output: crate::ResourceResultSchema")]
|
||||
| ------------------------------------- required by this bound in `gotham_restful::EndpointWithSchema::Output`
|
||||
|
||||
error[E0277]: the trait bound `FooResponse: ResourceResult` is not satisfied
|
||||
--> $DIR/invalid_return_type.rs:12:18
|
||||
|
|
||||
|
|
Loading…
Add table
Reference in a new issue