From 681482ece308c4f86597bdd07e871bd8a82ad61b Mon Sep 17 00:00:00 2001 From: Dominic Date: Mon, 30 Sep 2019 20:58:15 +0200 Subject: [PATCH] introduce openapitype --- src/lib.rs | 34 ++++++++++++- src/openapi/mod.rs | 3 ++ src/{openapi.rs => openapi/router.rs} | 4 +- src/openapi/types.rs | 69 +++++++++++++++++++++++++++ src/result.rs | 20 ++++++-- src/routing.rs | 2 +- 6 files changed, 126 insertions(+), 6 deletions(-) create mode 100644 src/openapi/mod.rs rename src/{openapi.rs => openapi/router.rs} (97%) create mode 100644 src/openapi/types.rs diff --git a/src/lib.rs b/src/lib.rs index 2a12070..0506d71 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,13 +2,18 @@ #[macro_use] extern crate serde; pub use hyper::StatusCode; +#[cfg(not(feature = "openapi"))] +use serde::Serialize; pub mod helper; #[cfg(feature = "openapi")] pub mod openapi; #[cfg(feature = "openapi")] -pub use openapi::{GetOpenapi, OpenapiRouter}; +pub use openapi::{ + router::{GetOpenapi, OpenapiRouter}, + types::OpenapiType +}; mod resource; pub use resource::{ @@ -29,3 +34,30 @@ mod routing; pub use routing::{DrawResources, DrawResourceRoutes}; #[cfg(feature = "openapi")] pub use routing::WithOpenapi; + + +/// A type that can be used inside a request or response body. Implemented for every type +/// that is serializable with serde, however, it is recommended to use the rest_struct! +/// macro to create one. +#[cfg(not(feature = "openapi"))] +pub trait ResourceType : Serialize +{ +} + +#[cfg(not(feature = "openapi"))] +impl ResourceType for T +{ +} + +/// A type that can be used inside a request or response body. Implemented for every type +/// that is serializable with serde, however, it is recommended to use the rest_struct! +/// macro to create one. +#[cfg(feature = "openapi")] +pub trait ResourceType : OpenapiType +{ +} + +#[cfg(feature = "openapi")] +impl ResourceType for T +{ +} diff --git a/src/openapi/mod.rs b/src/openapi/mod.rs new file mode 100644 index 0000000..5c19494 --- /dev/null +++ b/src/openapi/mod.rs @@ -0,0 +1,3 @@ + +pub mod router; +pub mod types; diff --git a/src/openapi.rs b/src/openapi/router.rs similarity index 97% rename from src/openapi.rs rename to src/openapi/router.rs index 7d36973..5de695f 100644 --- a/src/openapi.rs +++ b/src/openapi/router.rs @@ -14,7 +14,9 @@ use gotham::{ use indexmap::IndexMap; use log::error; use mime::{APPLICATION_JSON, TEXT_PLAIN}; -use openapiv3::{MediaType, OpenAPI, Operation, PathItem, Paths, ReferenceOr, ReferenceOr::Item, Response, Responses, Server, StatusCode}; +use openapiv3::{ + MediaType, OpenAPI, Operation, PathItem, Paths, ReferenceOr, ReferenceOr::Item, Response, Responses, Server, StatusCode +}; use serde::de::DeserializeOwned; use std::panic::RefUnwindSafe; diff --git a/src/openapi/types.rs b/src/openapi/types.rs new file mode 100644 index 0000000..ba37f61 --- /dev/null +++ b/src/openapi/types.rs @@ -0,0 +1,69 @@ +use indexmap::IndexMap; +use openapiv3::{ + IntegerType, NumberType, ObjectType, SchemaKind, StringType, Type +}; +use serde::Serialize; + + +pub trait OpenapiType : Serialize +{ + fn to_schema() -> SchemaKind; +} + +impl OpenapiType for () +{ + fn to_schema() -> SchemaKind + { + SchemaKind::Type(Type::Object(ObjectType::default())) + } +} + +impl OpenapiType for bool +{ + fn to_schema() -> SchemaKind + { + SchemaKind::Type(Type::Boolean{}) + } +} + +macro_rules! int_types { + ($($int_ty:ty),*) => {$( + impl OpenapiType for $int_ty + { + fn to_schema() -> SchemaKind + { + SchemaKind::Type(Type::Integer(IntegerType::default())) + } + } + )*} +} + +int_types!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128); + +macro_rules! num_types { + ($($num_ty:ty),*) => {$( + impl OpenapiType for $num_ty + { + fn to_schema() -> SchemaKind + { + SchemaKind::Type(Type::Number(NumberType::default())) + } + } + )*} +} + +num_types!(f32, f64); + +macro_rules! str_types { + ($($str_ty:ty),*) => {$( + impl OpenapiType for $str_ty + { + fn to_schema() -> SchemaKind + { + SchemaKind::Type(Type::String(StringType::default())) + } + } + )*} +} + +str_types!(String, &str); diff --git a/src/result.rs b/src/result.rs index c75c5f6..79f42c8 100644 --- a/src/result.rs +++ b/src/result.rs @@ -1,4 +1,5 @@ -use crate::StatusCode; +use crate::{ResourceType, StatusCode}; +use openapiv3::SchemaKind; use serde::Serialize; use serde_json::error::Error as SerdeJsonError; use std::error::Error; @@ -7,6 +8,9 @@ use std::error::Error; pub trait ResourceResult { fn to_json(&self) -> Result<(StatusCode, String), SerdeJsonError>; + + #[cfg(feature = "openapi")] + fn to_schema() -> SchemaKind; } /// The default json returned on an 500 Internal Server Error. @@ -28,7 +32,7 @@ impl From for ResourceError } } -impl ResourceResult for Result +impl ResourceResult for Result { fn to_json(&self) -> Result<(StatusCode, String), SerdeJsonError> { @@ -40,6 +44,11 @@ impl ResourceResult for Result } }) } + + fn to_schema() -> SchemaKind + { + R::to_schema() + } } /// This can be returned from a resource when there is no cause of an error. @@ -53,10 +62,15 @@ impl From for Success } } -impl ResourceResult for Success +impl ResourceResult for Success { fn to_json(&self) -> Result<(StatusCode, String), SerdeJsonError> { Ok((StatusCode::OK, serde_json::to_string(&self.0)?)) } + + fn to_schema() -> SchemaKind + { + T::to_schema() + } } diff --git a/src/routing.rs b/src/routing.rs index a7ea592..726dc85 100644 --- a/src/routing.rs +++ b/src/routing.rs @@ -4,7 +4,7 @@ use crate::{ StatusCode }; #[cfg(feature = "openapi")] -use crate::openapi::OpenapiRouter; +use crate::OpenapiRouter; use futures::{ future::{Future, err, ok},