jonasbb / serde_with

This crate provides custom de/serialization helpers to use in combination with serde's `with`-annotation and with the improved `serde_as`-annotation.
https://docs.rs/serde_with
Apache License 2.0
638 stars 67 forks source link

Unable to use `serde_with::serde_as` in conjunction with `schemars(schema_with)` #712

Closed indietyp closed 6 months ago

indietyp commented 6 months ago

I am trying to properly encode Base64 encoded data using schemars, but I am failing while the schemars_0_8 feature is enabled. Base64 does not implement JsonSchemaAs, so I went ahead and tried to implement it myself using the schema_with annotation.

#[serde_with::serde_as]
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(rename_all = "camelCase")]
pub struct Image {
    #[serde_as(as = "serde_with::base64::Base64")]
    #[cfg_attr(feature = "schemars", schemars(schema_with = "base_64_schema"))]
    pub buffer: Vec<u8>,
}

#[cfg(feature = "schemars")]
fn base_64_schema(_: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
    // These properties are valid JSON-schema properties, but they are not supported by schemars
    let mut extensions = std::collections::BTreeMap::new();
    extensions.insert(
        "contentEncoding".to_owned(),
        serde_json::Value::from("base64"),
    );
    extensions.insert(
        "contentMediaType".to_owned(),
        serde_json::Value::from("image/*"),
    );

    schemars::schema::SchemaObject {
        instance_type: Some(schemars::schema::InstanceType::String.into()),
        extensions,
        ..schemars::schema::SchemaObject::default()
    }
    .into()
}

This fails with the error: schemars attribute cannot contain both with and schema_with

any help would be immensely appreciated. Thank you so much for the great library and overall integration of schemars into it!

indietyp commented 6 months ago

I just found out that schemars = false works on a container level, but something similar would be great on a per field level.

jonasbb commented 6 months ago

The macro should handle such conflicts. There is a test, but it might only work for schemars(with = ...) and not schemars(schema_with = ...).

https://github.com/jonasbb/serde_with/blob/f30519a0a6df1c6acd463bb7755ff1005193dcbb/serde_with/tests/schemars_0_8.rs#L96-L118

You should be able to work around this for now, by using a type and with instead of schema_with.

The schema_with seems to have an identical functionality to with, but with different syntax. That in that case, the macro should detect both. I will check how to update the serde_as macro here.

jonasbb commented 6 months ago

A fix for this is released in v3.7.0