Skip to content

Custom (de)serializers #782

@djrodgerspryor

Description

@djrodgerspryor

Thanks for making cynic: it's great!

I'm currently using it to talk to an API which works with non-rfc3339 timestamps (they look like: 2023-09-27T18:42:31 - note the lack of an offset at the end). I've added chrono::DateTime as a scalar type as per the docs:

cynic::impl_scalar!(chrono::DateTime<chrono::Utc>, schema::ISODateTime);

But the lack of an offset makes chrono grumpy when parsing these values. Normally I'd handle this with a custom deserialize_with helper in serde. Something like:

fn generous_datetime_parser<'de, D>(
    deserializer: D,
) -> Result<chrono::DateTime<chrono::Utc>, D::Error>
where
    D: serde::Deserializer<'de>,
{
    use serde::Deserialize;

    let value = String::deserialize(deserializer)?;

    chrono::DateTime::parse_from_rfc3339(value.as_str())
        // Try adding a timezone (assume UTC) since those are often missing
        .or_else(|_| chrono::DateTime::parse_from_rfc3339(format!("{}+00:00", &value).as_str()))
        // Try adding a time component in case we were just given a date
        .or_else(|_| {
            chrono::DateTime::parse_from_rfc3339(format!("{}T00:00:00+00:00", &value).as_str())
        })
        .map_err(|e| {
            serde::de::Error::custom(format!(
                "Unable to parse chrono::DateTime from string ({}): {:?}",
                value, e
            ))
        })
        .map(|dt| dt.with_timezone(&chrono::Utc))
}

...

#[derive(cynic::QueryFragment, Debug, serde::Serialize)]
#[cynic(schema = "my_schema")]
struct Foo {
    #[serde(deserialize_with = "generous_datetime_parser")]
    created: chrono::DateTime<chrono::Utc>,
}

Using the deserialize_with serde option as above actually compiles, but it seems to do nothing, I'm guessing because of how cynic handles deserializing the scalar types internally. Is there already a supported way to do this in cynic, or at least a workaround to hook into the deserialization logic?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions