Software & Apps

SA 155FB3DF9D998E6BBBBBBBBBBBBBBBBBBBBBBBBBBBBBABBABBBROS7AECB7CA49E9F07D5D5 · Manmatter / at work

crates.io
Documentation
Download crates.io

Never stop the first mistake of the obesity.

ℹ️ This is a MAAGMATTER project. Check our Page of landing If you are looking for Rust Consulting or training!

serde is THE RUST LIBRARY FOR (DE) SERIALIZATION.
There is a catch, yet: serde designed to abort aborts when an error occurred. Becomes an issue when dependent on serde For the consignment of the given payment user – for example a request to a restful API.
There may be many errors in submitted payload, but serde_json

Report only the first it encountered before ceasing to dissipate. The API consumer then forced into a slow and failing feedback loop:

  1. Sending Request
  2. Receive a wrong return
  3. Fix the error
  4. Back to 1., until no more errors will be carried

That’s a bad developer experience. We have to make it better!
We should report multiple Often, in such a decrease in the number of API interactions needed to meet a well-formed payload.

That is the problem eserde was born to resolve.

Case Study: An Invalid JSON Payolload

Let us consider this schema as an example of what we have mentioned:

#(derive(Debug, serde::Deserialize))
struct Package {
    version: Version,
    source: String,
}

#(derive(Debug, eserde::Deserialize))
struct Version {
    major: u32,
    minor: u32,
    patch: u32,
}

Let’s try to grill an invalid JSON choose it by serde_json:

let payload = r#"
    {
        "version": {
            "major": 1,
            "minor": "2"
        },
        "source": null
    }"#;
let error = serde_json::from_str::<Package>(&payload).unwrap_err();
assert_eq!(
    error.to_string(),
    r#"invalid type: string "2", expected u32 at line 5 column 24"#
);

The first error is returned, as expected. But we know there’s more than that!
We lost in patch field of Version Structure and the source The field cannot be null.
We’ll Move eserde:

#(derive(Debug, eserde::Deserialize))
//              ^^^^^^^^^^^^^^^^^^^
//          Using `eserde::Deserialize`
//        instead of `serde::Deserialize`!
struct Package {
    version: Version,
    source: String,
}

#(derive(Debug, eserde::Deserialize))
struct Version {
    major: u32,
    minor: u32,
    patch: u32,
}

let payload = r#"
    {
        "version": {
            "major": 1,
            "minor": "2"
        },
        "source": null
    }"#;
let errors = eserde::json::from_str::<Package>(&payload).unwrap_err();
//           ^^^^^^^^^^^^
//      We're not using `serde_json` directly here!
assert_eq!(
    errors.to_string(),
    r#"Something went wrong during deserialization:
- version.minor: invalid type: string "2", expected u32 at line 5 column 24
- version: missing field `patch`
- source: invalid type: null, expected a string at line 7 column 22
"#
);

Better, aren’t you?
We can now notify users to one to go that they need to adjust three different schema breaches.

Usage eserde In your projects, add the following dependencies to your Cargo.toml:

(dependencies)
eserde = { version = "0.1" }
serde = "1"

You must be:

  • Replace all instances of #(derive(serde::Deserialize)) OTHERS #(derive(eserde::Deserialize))
  • Move to a eserde-Use function of enjoyment

eserde provides first class support for JSON Weserialization, Gated behind json Freight.

(dependencies)
# Activating the `json` feature
eserde = { version = "0.1", features = ("json") }
serde = "1"

If you work with JSON:

  • replaced serde_json::from_str OTHERS eserde::json::from_str
  • replaced serde_json::from_slice OTHERS eserde::json::from_slice

eserde::json Consulting not supported from a reader, ie no equals
serde_json::from_reader.

There is also a axum together, eserde_axum. It gives one eserde-Pgaopered JSON Extractor as a drop-in replacement for axumEstablished one.

The method used in eserde The compatible, in principle, in all that exists serde-baseed delerizers.
referring the source code of eserde::json::from_str

As a plan to follow for building a eserde-Create deesialization function for another format.

eserde designed to be the maximum highest serde.

derive(eserde::Deserialize) carry out both
serde::Deserialize and eserde::EDeserializeHonoring the behavior of all that serde traits it supports.

If one of your fields do not apply eserde::EDeserializeYou can annot it
#(eserde(compat)) To drop back serdeDefault Defe Defa default lockialization lookicization for that side of input.

#(derive(eserde::Deserialize))
struct Point {
    // 👇 Use the `eserde::compat` attribute if you need to use
    //    a field type that doesn't implement `eserde::EDeserialize`
    //    and you can't derive `eserde::EDeserialize` for it (e.g. a third-party type)
    #(eserde(compat))
    x: Latitude,
    // (...)
}

Check the documentation of eserdeget the macro for more details.

But how eserde actually worked? Let’s keep using JSON as an example – equally applicable to other data formats.
We try to weserize input by serde_json. If observing successes, we will return the brave amount to the caller.

// The source code for  `eserde::json::from_str`.
pub fn from_str<'a, T>(s: &'a str) -> Result<T, DeserializationErrors>
where
    T: EDeserialize<'a>,
{
    let mut de = serde_json::Deserializer::from_str(s);
    let error = match T::deserialize(&mut de) {
        Ok(v) => {
            return Ok(v);
        }
        Err(e) => e,
    };
    // (...)
}

There’s nothing new on a happy path – this is the same thing you do now with your own applications with vanilla serde. We change the unhappy road.
Instead of returning to the caller error reported to serde_jsonWe make one pass through the input of use
eserde::EDeserialize::deserialize_for_errors:

pub fn from_str<'a, T>(s: &'a str) -> Result<T, DeserializationErrors>
where
    T: EDeserialize<'a>,
{
    // (...) The code above (...)
    let _guard = ErrorReporter::start_deserialization();

    let mut de = serde_json::Deserializer::from_str(s);
    let de = path::Deserializer::new(&mut de);

    let errors = match T::deserialize_for_errors(de) {
        Ok(_) => vec!(),
        Err(_) => ErrorReporter::take_errors(),
    };
    let errors = if errors.is_empty() {
        vec!(DeserializationError {
            path: None,
            details: error.to_string(),
        })
    } else {
        errors
    };

    Err(DeserializationErrors::from(errors))
}

EDeserialize::deserialize_for_errors formed the mistakes of disapproval of a thread-local buffer, began with ErrorReporter::start_deserialization and taken later in ErrorReporter::take_errors.

This underlying complexity is attached to eserde::jsonTasks, but useful to have a model of thinking what is happening under the hood when you plan to adopt eserde.

Limits and downsides

eserde A new library – may have issues and bugs not yet found. Try this before using it in production. If you have experienced any problems, please open an issue with our Gushup in the gutuph.

Except for defects, there are some depletions of eserdeDesign Design:

  • The input should be visited twice, so it cannot save from an unbearable reader.
  • Input should be visited twice, so this happens slow than the one serde::Deserialize
    pass.
  • #(derive(eserde::Deserialize)) creates additional code than serde::Deserialize (changed twice as much), so there’s a bigger effect on Vanilla serde in your compilment times.

We believe the trade-off is useful for players to deal with the user, but you have to walk in your eyes open.

We plan to add first class support for additional data formats, in particular YAML and Toml. They are often used for configuration files, another scenario in which batch error can improve our developer experience.

We plan to increase support over more #(serde) characteristics, thus shortened the friction to adopt eserde in your cenerebase.

We plan to add first class support for validation, with a syntax similar to garde

and validator. The key difference: Validation will be made as part of the process of de -ferialization. It is not necessary to remember to call .validate() Then.

Copyright © 2025- Mainmatter GmbH (https://mainmatter.com), released under
with and Apache licenses.


https://opengraph.githubassets.com/97d62c907cf1dc90f617d385a248b2c2b09ed4e6307e99031c2ae87eee5cd3b7/mainmatter/eserde

2025-02-18 22:49:00

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button