use poem::{route::Route, Error, IntoResponse, RequestBody, Result};
use crate::{
payload::Payload,
registry::{MetaAPI, MetaMediaType, MetaRequest, MetaResponse, MetaResponses, Registry},
};
#[poem::async_trait]
pub trait Request: Sized {
fn meta() -> MetaRequest;
fn register(registry: &mut Registry);
async fn from_request(request: &poem::Request, body: &mut RequestBody) -> Result<Self>;
}
#[poem::async_trait]
impl<T: Payload> Request for T {
fn meta() -> MetaRequest {
MetaRequest {
description: None,
content: vec![MetaMediaType {
content_type: T::CONTENT_TYPE,
schema: T::schema_ref(),
}],
required: true,
}
}
fn register(registry: &mut Registry) {
T::register(registry);
}
async fn from_request(request: &poem::Request, body: &mut RequestBody) -> Result<Self> {
T::from_request(request, body).await
}
}
pub trait Response: IntoResponse + Sized {
const BAD_REQUEST_HANDLER: bool = false;
fn meta() -> MetaResponses;
fn register(registry: &mut Registry);
#[allow(unused_variables)]
fn from_parse_request_error(err: Error) -> Self {
unreachable!()
}
}
impl Response for () {
fn meta() -> MetaResponses {
MetaResponses {
responses: vec![MetaResponse {
description: None,
status: Some(200),
content: vec![],
}],
}
}
fn register(_registry: &mut Registry) {}
}
impl<T: Payload> Response for T {
fn meta() -> MetaResponses {
MetaResponses {
responses: vec![MetaResponse {
description: None,
status: Some(200),
content: vec![MetaMediaType {
content_type: T::CONTENT_TYPE,
schema: T::schema_ref(),
}],
}],
}
}
fn register(registry: &mut Registry) {
T::register(registry);
}
}
pub trait API: Sized {
fn meta() -> Vec<MetaAPI>;
fn register(registry: &mut Registry);
fn add_routes(self, route: Route) -> Route;
fn combine<T: API>(self, other: T) -> CombinedAPI<Self, T> {
CombinedAPI(self, other)
}
}
pub struct CombinedAPI<A, B>(A, B);
impl<A: API, B: API> API for CombinedAPI<A, B> {
fn meta() -> Vec<MetaAPI> {
let mut metadata = A::meta();
metadata.extend(B::meta());
metadata
}
fn register(registry: &mut Registry) {
A::register(registry);
B::register(registry);
}
fn add_routes(self, route: Route) -> Route {
self.1.add_routes(self.0.add_routes(route))
}
}