use crate::tina::data::app_error::AppError;
use crate::tina::openapi::parameter::Parameter;
use crate::tina::openapi::schema::Schema;
use crate::tina::server::http::route::{RouteBaseConfig, RouteBuilder};
use std::any::type_name;
use crate::app_system_error;
use crate::tina::data::api_schema::ApiSchema;
use crate::tina::data::json::ToJson;
use crate::tina::data::response_data::ResData;
use crate::tina::data::response_page::ResPage;
use crate::tina::data::response_stream::ResStream;
use crate::tina::data::AppResult;
use crate::tina::server::application::Application;
use crate::tina::server::http::ntex::delegate::RouteHandlerDelegate;
use crate::tina::server::http::request::{ReqJson, ReqMetadata, ReqMultipart, ReqParam, ReqPath};
use crate::tina::server::http::response::{ResRaw, ResponseAttribute};
use crate::tina::server::session::Session;
use crate::tina::util::json::JsonUtil;
use crate::tina::validator::Validated;
use itertools::Itertools;
use ntex::web::{ErrorRenderer, FromRequest, Handler, Responder, Route};
use serde::de::DeserializeOwned;
use serde::Serialize;
use serde_json::Value;
use std::fmt::Debug;
use std::future::Future;
pub struct RouteConfig {
pub(crate) route: Option<Route<AppError>>,
pub(crate) config: RouteBaseConfig,
}
impl RouteBuilder {
pub fn to<F, Args>(&mut self, handler: F) -> RouteConfig
where
F: Handler<Args, AppError> + Clone + 'static,
Args: FromApiRequest<AppError> + 'static,
Args::Error: Into<AppError>,
F::Output: ApiResponder<AppError>,
{
self.request_parameter = Args::get_request_parameter();
self.request_body = Args::get_request_body();
self.response_body = F::Output::get_response_body();
self.produces = F::Output::get_produces();
self.consumes = Args::get_consumes();
self.handler_name = type_name::<F>().to_string();
let mut route_config = self.to_route();
let mut route = Route::<AppError>::new().method(route_config.config.method.to_method());
route = match route_config.config.should_delegate_handler() {
true => Route::to(route, RouteHandlerDelegate::new(handler)),
false => Route::to(route, handler),
};
route_config.route = Some(route);
route_config
}
}
pub trait FromApiRequest<Err>: FromRequest<Err, Error = Err> {
fn get_consumes() -> Vec<String>
where
Self: Sized;
fn get_request_parameter() -> Option<Vec<Parameter>>
where
Self: Sized;
fn get_request_body() -> Option<Schema>
where
Self: Sized;
fn to_param_value(&self) -> AppResult<Value>;
}
pub trait ApiResponder<Err = AppError>: Responder<Err> {
fn get_produces() -> Vec<String>
where
Self: Sized;
fn get_response_body() -> Option<Schema>
where
Self: Sized;
fn is_success(&self) -> bool;
}
pub trait ApiHandler<T, Err>: Handler<T, Err>
where
Err: ErrorRenderer,
{
type Output: ApiResponder<Err>;
type Future<'f>: Future<Output = <Self as ApiHandler<T, Err>>::Output>
where
Self: 'f;
fn call(&self, param: T) -> <Self as ApiHandler<T, Err>>::Future<'_>;
}
impl<H, T, Err> ApiHandler<T, Err> for H
where
H: Handler<T, Err>,
H::Output: ApiResponder<Err>,
Err: ErrorRenderer,
{
type Output = H::Output;
type Future<'f> = H::Future<'f> where Self: 'f;
fn call(&self, param: T) -> <Self as ApiHandler<T, Err>>::Future<'_> {
<H as Handler<T, Err>>::call(&self, param)
}
}
impl<D: DeserializeOwned + Serialize + Validated + ApiSchema> FromApiRequest<AppError> for ReqJson<D> {
fn get_consumes() -> Vec<String>
where
Self: Sized,
{
vec!["application/json; charset=UTF-8".to_owned()]
}
fn get_request_parameter() -> Option<Vec<Parameter>>
where
Self: Sized,
{
None
}
fn get_request_body() -> Option<Schema>
where
Self: Sized,
{
<ReqJson<D> as ApiSchema>::get_request_body()
}
fn to_param_value(&self) -> AppResult<Value> {
Ok(self.to_json_value())
}
}
impl<D: DeserializeOwned + Serialize + Validated + ApiSchema> FromApiRequest<AppError> for ReqPath<D> {
fn get_consumes() -> Vec<String>
where
Self: Sized,
{
vec![]
}
fn get_request_parameter() -> Option<Vec<Parameter>>
where
Self: Sized,
{
<ReqPath<D> as ApiSchema>::get_parameters()
}
fn get_request_body() -> Option<Schema>
where
Self: Sized,
{
None
}
fn to_param_value(&self) -> AppResult<Value> {
let value = self.to_json_value();
match value {
Value::Object(v) => Ok(Value::Object(v)),
_ => {
let name = self
.names()
.iter()
.next()
.map(|v| v.to_string())
.ok_or_else(|| app_system_error!("no param name found in ReqPath: {}", type_name::<Self>()))?;
let mut map = serde_json::Map::new();
map.insert(name, value);
Ok(Value::Object(map))
}
}
}
}
impl<D: DeserializeOwned + Serialize + Validated + ApiSchema> FromApiRequest<AppError> for ReqParam<D> {
fn get_consumes() -> Vec<String>
where
Self: Sized,
{
vec![]
}
fn get_request_parameter() -> Option<Vec<Parameter>>
where
Self: Sized,
{
<ReqParam<D> as ApiSchema>::get_parameters()
}
fn get_request_body() -> Option<Schema>
where
Self: Sized,
{
None
}
fn to_param_value(&self) -> AppResult<Value> {
Ok(self.to_json_value())
}
}
impl<D: DeserializeOwned + Serialize + Validated + ApiSchema> FromApiRequest<AppError> for ReqMultipart<D> {
fn get_consumes() -> Vec<String>
where
Self: Sized,
{
vec!["multipart/form-data".to_owned()]
}
fn get_request_parameter() -> Option<Vec<Parameter>>
where
Self: Sized,
{
<ReqMultipart<D> as ApiSchema>::get_parameters()
}
fn get_request_body() -> Option<Schema>
where
Self: Sized,
{
None
}
fn to_param_value(&self) -> AppResult<Value> {
Ok(self.to_json_value())
}
}
impl FromApiRequest<AppError> for Session {
fn get_consumes() -> Vec<String>
where
Self: Sized,
{
vec![]
}
fn get_request_parameter() -> Option<Vec<Parameter>>
where
Self: Sized,
{
None
}
fn get_request_body() -> Option<Schema>
where
Self: Sized,
{
None
}
fn to_param_value(&self) -> AppResult<Value> {
Ok(Value::Null)
}
}
impl FromApiRequest<AppError> for Application {
fn get_consumes() -> Vec<String>
where
Self: Sized,
{
vec![]
}
fn get_request_parameter() -> Option<Vec<Parameter>>
where
Self: Sized,
{
None
}
fn get_request_body() -> Option<Schema>
where
Self: Sized,
{
None
}
fn to_param_value(&self) -> AppResult<Value> {
Ok(Value::Null)
}
}
impl FromApiRequest<AppError> for ReqMetadata {
fn get_consumes() -> Vec<String>
where
Self: Sized,
{
vec![]
}
fn get_request_parameter() -> Option<Vec<Parameter>>
where
Self: Sized,
{
None
}
fn get_request_body() -> Option<Schema>
where
Self: Sized,
{
None
}
fn to_param_value(&self) -> AppResult<Value> {
Ok(Value::Null)
}
}
impl FromApiRequest<AppError> for () {
fn get_consumes() -> Vec<String>
where
Self: Sized,
{
vec![]
}
fn get_request_parameter() -> Option<Vec<Parameter>>
where
Self: Sized,
{
None
}
fn get_request_body() -> Option<Schema>
where
Self: Sized,
{
None
}
fn to_param_value(&self) -> AppResult<Value> {
Ok(Value::Null)
}
}
impl<T1> FromApiRequest<AppError> for (T1,)
where
T1: FromApiRequest<AppError> + 'static,
{
fn get_consumes() -> Vec<String>
where
Self: Sized,
{
T1::get_consumes()
}
fn get_request_parameter() -> Option<Vec<Parameter>>
where
Self: Sized,
{
let mut params = Vec::new();
if let Some(mut v) = T1::get_request_parameter() {
params.append(&mut v);
}
match params.is_empty() {
true => None,
false => Some(params),
}
}
fn get_request_body() -> Option<Schema>
where
Self: Sized,
{
if let Some(v) = T1::get_request_body() {
return Some(v);
}
None
}
fn to_param_value(&self) -> AppResult<Value> {
self.0.to_param_value()
}
}
impl<T1, T2> FromApiRequest<AppError> for (T1, T2)
where
T1: FromApiRequest<AppError> + 'static,
T2: FromApiRequest<AppError> + 'static,
{
fn get_consumes() -> Vec<String>
where
Self: Sized,
{
T1::get_consumes().into_iter().merge(T2::get_consumes().into_iter()).collect()
}
fn get_request_parameter() -> Option<Vec<Parameter>>
where
Self: Sized,
{
let mut params = Vec::new();
if let Some(mut v) = T1::get_request_parameter() {
params.append(&mut v);
}
if let Some(mut v) = T2::get_request_parameter() {
params.append(&mut v);
}
match params.is_empty() {
true => None,
false => Some(params),
}
}
fn get_request_body() -> Option<Schema>
where
Self: Sized,
{
if let Some(v) = T1::get_request_body() {
return Some(v);
}
if let Some(v) = T2::get_request_body() {
return Some(v);
}
None
}
fn to_param_value(&self) -> AppResult<Value> {
let v1 = JsonUtil::merge_value(self.0.to_param_value()?, self.1.to_param_value()?)?;
Ok(v1)
}
}
impl<T1, T2, T3> FromApiRequest<AppError> for (T1, T2, T3)
where
T1: FromApiRequest<AppError> + 'static,
T2: FromApiRequest<AppError> + 'static,
T3: FromApiRequest<AppError> + 'static,
{
fn get_consumes() -> Vec<String>
where
Self: Sized,
{
T1::get_consumes().into_iter().merge(T2::get_consumes().into_iter()).merge(T3::get_consumes().into_iter()).collect()
}
fn get_request_parameter() -> Option<Vec<Parameter>>
where
Self: Sized,
{
let mut params = Vec::new();
if let Some(mut v) = T1::get_request_parameter() {
params.append(&mut v);
}
if let Some(mut v) = T2::get_request_parameter() {
params.append(&mut v);
}
if let Some(mut v) = T3::get_request_parameter() {
params.append(&mut v);
}
match params.is_empty() {
true => None,
false => Some(params),
}
}
fn get_request_body() -> Option<Schema>
where
Self: Sized,
{
if let Some(v) = T1::get_request_body() {
return Some(v);
}
if let Some(v) = T2::get_request_body() {
return Some(v);
}
if let Some(v) = T3::get_request_body() {
return Some(v);
}
None
}
fn to_param_value(&self) -> AppResult<Value> {
let v1 = JsonUtil::merge_value(self.0.to_param_value()?, self.1.to_param_value()?)?;
let v2 = JsonUtil::merge_value(v1, self.2.to_param_value()?)?;
Ok(v2)
}
}
impl<T1, T2, T3, T4> FromApiRequest<AppError> for (T1, T2, T3, T4)
where
T1: FromApiRequest<AppError> + 'static,
T2: FromApiRequest<AppError> + 'static,
T3: FromApiRequest<AppError> + 'static,
T4: FromApiRequest<AppError> + 'static,
{
fn get_consumes() -> Vec<String>
where
Self: Sized,
{
T1::get_consumes()
.into_iter()
.merge(T2::get_consumes().into_iter())
.merge(T3::get_consumes().into_iter())
.merge(T4::get_consumes().into_iter())
.collect()
}
fn get_request_parameter() -> Option<Vec<Parameter>>
where
Self: Sized,
{
let mut params = Vec::new();
if let Some(mut v) = T1::get_request_parameter() {
params.append(&mut v);
}
if let Some(mut v) = T2::get_request_parameter() {
params.append(&mut v);
}
if let Some(mut v) = T3::get_request_parameter() {
params.append(&mut v);
}
if let Some(mut v) = T4::get_request_parameter() {
params.append(&mut v);
}
match params.is_empty() {
true => None,
false => Some(params),
}
}
fn get_request_body() -> Option<Schema>
where
Self: Sized,
{
if let Some(v) = T1::get_request_body() {
return Some(v);
}
if let Some(v) = T2::get_request_body() {
return Some(v);
}
if let Some(v) = T3::get_request_body() {
return Some(v);
}
if let Some(v) = T4::get_request_body() {
return Some(v);
}
None
}
fn to_param_value(&self) -> AppResult<Value> {
let v1 = JsonUtil::merge_value(self.0.to_param_value()?, self.1.to_param_value()?)?;
let v2 = JsonUtil::merge_value(v1, self.2.to_param_value()?)?;
let v3 = JsonUtil::merge_value(v2, self.3.to_param_value()?)?;
Ok(v3)
}
}
impl<T1, T2, T3, T4, T5> FromApiRequest<AppError> for (T1, T2, T3, T4, T5)
where
T1: FromApiRequest<AppError> + 'static,
T2: FromApiRequest<AppError> + 'static,
T3: FromApiRequest<AppError> + 'static,
T4: FromApiRequest<AppError> + 'static,
T5: FromApiRequest<AppError> + 'static,
{
fn get_consumes() -> Vec<String>
where
Self: Sized,
{
T1::get_consumes()
.into_iter()
.merge(T2::get_consumes().into_iter())
.merge(T3::get_consumes().into_iter())
.merge(T4::get_consumes().into_iter())
.merge(T5::get_consumes().into_iter())
.collect()
}
fn get_request_parameter() -> Option<Vec<Parameter>>
where
Self: Sized,
{
let mut params = Vec::new();
if let Some(mut v) = T1::get_request_parameter() {
params.append(&mut v);
}
if let Some(mut v) = T2::get_request_parameter() {
params.append(&mut v);
}
if let Some(mut v) = T3::get_request_parameter() {
params.append(&mut v);
}
if let Some(mut v) = T4::get_request_parameter() {
params.append(&mut v);
}
if let Some(mut v) = T5::get_request_parameter() {
params.append(&mut v);
}
match params.is_empty() {
true => None,
false => Some(params),
}
}
fn get_request_body() -> Option<Schema>
where
Self: Sized,
{
if let Some(v) = T1::get_request_body() {
return Some(v);
}
if let Some(v) = T2::get_request_body() {
return Some(v);
}
if let Some(v) = T3::get_request_body() {
return Some(v);
}
if let Some(v) = T4::get_request_body() {
return Some(v);
}
if let Some(v) = T5::get_request_body() {
return Some(v);
}
None
}
fn to_param_value(&self) -> AppResult<Value> {
let v1 = JsonUtil::merge_value(self.0.to_param_value()?, self.1.to_param_value()?)?;
let v2 = JsonUtil::merge_value(v1, self.2.to_param_value()?)?;
let v3 = JsonUtil::merge_value(v2, self.3.to_param_value()?)?;
let v4 = JsonUtil::merge_value(v3, self.4.to_param_value()?)?;
Ok(v4)
}
}
impl<D: ApiResponder<AppError>> ApiResponder<AppError> for AppResult<D> {
fn get_produces() -> Vec<String>
where
Self: Sized,
{
D::get_produces()
}
fn get_response_body() -> Option<Schema>
where
Self: Sized,
{
D::get_response_body()
}
fn is_success(&self) -> bool {
match &self {
Ok(v) => v.is_success(),
Err(_) => false,
}
}
}
impl<D: Serialize + Debug + ApiSchema, Ext: Serialize + Debug + ApiSchema> ApiResponder<AppError> for ResData<D, Ext> {
fn get_produces() -> Vec<String>
where
Self: Sized,
{
vec!["application/json".to_owned()]
}
fn get_response_body() -> Option<Schema>
where
Self: Sized,
{
<ResData<D, Ext> as ApiSchema>::get_response()
}
fn is_success(&self) -> bool {
self.code.is_success()
}
}
impl<D: Serialize + Debug + ApiSchema> ApiResponder<AppError> for ResPage<D> {
fn get_produces() -> Vec<String>
where
Self: Sized,
{
vec!["application/json".to_owned()]
}
fn get_response_body() -> Option<Schema>
where
Self: Sized,
{
<ResPage<D> as ApiSchema>::get_response()
}
fn is_success(&self) -> bool {
self.code.is_success()
}
}
impl ApiResponder<AppError> for ResStream {
fn get_produces() -> Vec<String>
where
Self: Sized,
{
vec!["application/octet-stream".to_owned()]
}
fn get_response_body() -> Option<Schema>
where
Self: Sized,
{
<ResStream as ApiSchema>::get_response()
}
fn is_success(&self) -> bool {
self.success()
}
}
impl ApiResponder<AppError> for ResRaw {
fn get_produces() -> Vec<String>
where
Self: Sized,
{
vec![]
}
fn get_response_body() -> Option<Schema>
where
Self: Sized,
{
None
}
fn is_success(&self) -> bool {
self.success()
}
}