Skip to content

Commit

Permalink
feat(aide): added UseApi and into_api::<T>() which is made to use…
Browse files Browse the repository at this point in the history
… existing types for documenting types that do not implement aide types
  • Loading branch information
Wicpar committed Oct 19, 2023
1 parent 553702d commit c3087b8
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 1 deletion.
1 change: 1 addition & 0 deletions crates/aide/src/helpers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod no_api;
pub mod with_api;
pub mod use_api;
158 changes: 158 additions & 0 deletions crates/aide/src/helpers/use_api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
use std::marker::PhantomData;

use derive_more::{AsMut, AsRef, Deref, DerefMut};
use serde::{Deserialize, Serialize};

use crate::gen::GenContext;
use crate::openapi::{Operation, Response};
use crate::{OperationInput, OperationOutput};

/// helper trait to allow simplified use of [UseApi] in responses
pub trait IntoApi {
fn into_api<A>(self) -> UseApi<Self, A> where Self: Sized;
}

impl<T> IntoApi for T {
fn into_api<A>(self) -> UseApi<Self, A> where Self: Sized {
self.into()
}
}

/// Allows non [OperationInput] or [OperationOutput] types to be used in aide handlers with the api documentation of [A].
/// For types that already implement [OperationInput] or [OperationOutput] it overrides the documentation with the provided one.
#[derive(
Copy,
Clone,
Debug,
Ord,
PartialOrd,
Eq,
PartialEq,
Hash,
Serialize,
Deserialize,
Deref,
DerefMut,
AsRef,
AsMut,
)]
pub struct UseApi<T, A>(
#[as_ref]
#[as_mut]
#[deref]
#[deref_mut]
pub T,
pub PhantomData<A>,
);

impl<T, A> From<T> for UseApi<T, A> {
fn from(value: T) -> Self {
Self(value, Default::default())
}
}

impl<T, A> UseApi<T, A>
{
/// Unwraps [Self] into its inner type
pub fn into_inner(self) -> T {
self.0
}
}

impl<T, A> OperationInput for UseApi<T, A>
where
A: OperationInput,
{
fn operation_input(ctx: &mut GenContext, operation: &mut Operation) {
A::operation_input(ctx, operation)
}

fn inferred_early_responses(
ctx: &mut GenContext,
operation: &mut Operation,
) -> Vec<(Option<u16>, Response)> {
A::inferred_early_responses(ctx, operation)
}
}

impl<T, A> OperationOutput for UseApi<T, A>
where
A: OperationOutput,
{
type Inner = A::Inner;

fn operation_response(ctx: &mut GenContext, operation: &mut Operation) -> Option<Response> {
A::operation_response(ctx, operation)
}

fn inferred_responses(
ctx: &mut GenContext,
operation: &mut Operation,
) -> Vec<(Option<u16>, Response)> {
A::inferred_responses(ctx, operation)
}
}

#[cfg(feature = "axum")]
mod axum {
use axum::async_trait;
use axum::extract::{FromRequest, FromRequestParts};
use axum::response::{IntoResponse, IntoResponseParts, Response, ResponseParts};
use http::request::Parts;
use http::Request;

use crate::UseApi;

impl<T, A> IntoResponse for UseApi<T, A>
where
T: IntoResponse,
{
fn into_response(self) -> Response {
self.0.into_response()
}
}

impl<T, A> IntoResponseParts for UseApi<T, A>
where
T: IntoResponseParts,
{
type Error = T::Error;

fn into_response_parts(self, res: ResponseParts) -> Result<ResponseParts, Self::Error> {
self.0.into_response_parts(res)
}
}

#[async_trait]
impl<T, A, S> FromRequestParts<S> for UseApi<T, A>
where
T: FromRequestParts<S>,
S: Send + Sync,
{
type Rejection = T::Rejection;

async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
Ok(Self(
T::from_request_parts(parts, state).await?,
Default::default(),
))
}
}

#[async_trait]
impl<T, A, S, B> FromRequest<S, B> for UseApi<T, A>
where
T: FromRequest<S, B>,
S: Send + Sync,
B: Send + 'static,
{
type Rejection = T::Rejection;

async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> {
Ok(Self(
T::from_request(req, state).await?,
Default::default(),
))
}
}
}
2 changes: 1 addition & 1 deletion crates/aide/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ mod helpers;
#[cfg(feature = "redoc")]
pub mod redoc;

pub use helpers::{no_api::NoApi, with_api::ApiOverride, with_api::WithApi};
pub use helpers::{no_api::NoApi, with_api::ApiOverride, with_api::WithApi, use_api::UseApi};

pub use error::Error;
pub use operation::{OperationInput, OperationOutput};
Expand Down

0 comments on commit c3087b8

Please sign in to comment.