gengteng / axum-valid

axum-valid is a library that provides data validation extractors for the Axum web framework. It integrates validator, garde and validify, three popular validation crates in the Rust ecosystem, to offer convenient validation and data handling extractors for Axum applications.
MIT License
100 stars 4 forks source link

Support for aide #18

Closed javihc closed 8 months ago

javihc commented 8 months ago

Aide is one of the best openapi libraries for Axum but it is not compatible with axul-valid. Aide requires that the extractors implements the trait OperationIO. It would be great if axum-valid implements this trait under a feature.

https://github.com/tamasfe/aide

gengteng commented 8 months ago

@javihc

Good idea, I took a quick look at aide, is what I need to do just to add #[cfg_attr(feature = "aide", derive(aide::OperationIo))] to each extractors and that's it?

gengteng commented 8 months ago

@javihc

Regarding your feature request, I have added related code to the main branch to implement that new functionality. If convenient, please take a look at the latest main branch and let me know if it meets your needs. I would greatly appreciate if you could provide feedback on whether the current implementation works for your use case.

If the current implementation works for you, I plan to release this feature in version 0.14.0, thx.

javihc commented 8 months ago

It is not as simple as add derive(aide::OperationIo) becouse it doesnt add the correct documentation (See https://docs.rs/aide/latest/aide/derive.OperationIo.html#examples).

Derive it only make it compatible with aide but the documentation is lost. There is an option with this example but I don't try it.

#[derive(OperationIo)]
#[aide(
    input_with = "some_other::Json<T>",
    output_with = "some_other::Json<T>",
    json_schema
)]
struct Json<T>(pub T);

This is the actual implemetation of Json in aide:

impl<T> OperationInput for Json<T>
where
    T: JsonSchema,
{
    fn operation_input(ctx: &mut crate::gen::GenContext, operation: &mut Operation) {
        let schema = ctx.schema.subschema_for::<T>().into_object();
        let resolved_schema = ctx.resolve_schema(&schema);

        set_body(
            ctx,
            operation,
            RequestBody {
                description: resolved_schema
                    .metadata
                    .as_ref()
                    .and_then(|m| m.description.clone()),
                content: IndexMap::from_iter([(
                    "application/json".into(),
                    MediaType {
                        schema: Some(SchemaObject {
                            json_schema: schema.into(),
                            example: None,
                            external_docs: None,
                        }),
                        ..Default::default()
                    },
                )]),
                required: true,
                extensions: IndexMap::default(),
            },
        );
    }
}

The key is to return the implementation of the generic type. Maybe with

impl<T> OperationInput for Valid<T>
where
    T: OperationInput,
{
    fn operation_input(ctx: &mut crate::gen::GenContext, operation: &mut Operation) {
        T::operation_input(ctx, operation);
    }
}
gengteng commented 8 months ago

@javihc Try axum 0.14.0, should work now.