dyson_http 0.1.1

Dyson HTTP API Support Crate
Documentation
use axum::Router;
use utoipa::openapi::security::{ApiKey, ApiKeyValue, HttpAuthScheme, HttpBuilder, SecurityScheme};
use utoipa::{Modify, openapi::OpenApi};
use utoipa_axum::router::OpenApiRouter;
use utoipa_rapidoc::RapiDoc;
use utoipa_redoc::{Redoc, Servable};
use utoipa_scalar::{Scalar, Servable as ScalarServable};
use utoipa_swagger_ui::SwaggerUi;

pub struct ApiKeySecuritySchemeAddon;

impl Modify for ApiKeySecuritySchemeAddon {
    fn modify(&self, openapi: &mut OpenApi) {
        if let Some(components) = openapi.components.as_mut() {
            components.add_security_scheme(
                "api_key",
                SecurityScheme::ApiKey(ApiKey::Header(ApiKeyValue::new("todo_apikey"))),
            )
        }
    }
}

pub struct JwtSecuritySchemeAddon;

impl Modify for JwtSecuritySchemeAddon {
    fn modify(&self, openapi: &mut OpenApi) {
        if let Some(components) = openapi.components.as_mut() {
            components.add_security_scheme(
                "jwt",
                SecurityScheme::Http(
                    HttpBuilder::new()
                        .scheme(HttpAuthScheme::Bearer)
                        .bearer_format("JWT")
                        .build(),
                ),
            );
        }
    }
}

pub fn router_with_docs(router: OpenApiRouter) -> Router {
    let openapi_json = "/http/v1/openapi.json";
    let (router, api) = router.split_for_parts();
    let router = router
        .merge(SwaggerUi::new("/swagger-ui").url(openapi_json, api.clone()))
        .merge(Redoc::with_url("/redoc", api.clone()))
        .merge(RapiDoc::new(openapi_json).path("/rapidoc"))
        .merge(Scalar::with_url("/", api.clone()));
    router
}

#[macro_export]
macro_rules! route_docs_with_name {
    (
        $fn_expr:ident,
        desc=$desc:expr,
        tag=$tag:expr,
        res = $( ($status:literal, $resp_ty:ty) ),+ $(,)?
    ) => {
        pub fn $fn_expr(op: TransformOperation) -> TransformOperation {
            let op = op.description($desc).tag($tag);
            $( let op = op.response::<$status, $resp_ty>(); )+
            op
        }

    };
}

#[macro_export]
macro_rules! route_docs {
    (
        desc=$desc:expr,
        tag=$tag:expr,
        res = $( ($status:literal, $resp_ty:ty) ),+ $(,)?
    ) => {
        |op: TransformOperation| -> TransformOperation {
            let op = op.description($desc).tag($tag);
            $( let op = op.response::<$status, $resp_ty>(); )+
            op
        }
    };
}

#[macro_export]
macro_rules! endpoint {
(
    $(#[$attr:meta])*
    $process_fn:ident($($param:ident: $param_ty:ty),*)
) => {
    paste! {
        $(#[$attr])*
        async fn [<$process_fn _endpoint>](
            $($param: $param_ty),*
        ) -> impl IntoResponse {
            $process_fn($($param),*).await
        }
    }
    };
}

#[macro_export]
macro_rules! register_routes {
    ($($fn_name:ident),+ $(,)?) => {
        {
            use utoipa_axum::routes;
            let mut router = OpenApiRouter::new();
            $(
                router = router.routes(routes!($fn_name));
            )+
            router
        }
    };
}