#serde-json #json #json-error #json-path #serialization #serde #debugging

serde_json_path_to_error

A drop in replacement for serde_json where detailed errors are the default

6 releases

0.1.4 Oct 19, 2023
0.1.3 Oct 18, 2023
0.0.2 Oct 18, 2023

#356 in Encoding

Download history 188/week @ 2024-01-01 103/week @ 2024-01-08 152/week @ 2024-01-15 494/week @ 2024-01-22 96/week @ 2024-01-29 87/week @ 2024-02-05 460/week @ 2024-02-12 384/week @ 2024-02-19 686/week @ 2024-02-26 349/week @ 2024-03-04 633/week @ 2024-03-11 162/week @ 2024-03-18 35/week @ 2024-03-25 372/week @ 2024-04-01

1,208 downloads per month

MIT/Apache

14KB
130 lines

serde_json_path_to_error

License Latest version Latest Docs downloads-badge

API docs

A drop in replacement for serde_json with errors enriched by serde_path_to_error.

This is usually a better default since it makes it easier to debug when serialization or deserialization fails. Paths are particularly helpful when your schema is large or when it's difficult to see the raw data that causes an error.

This crate exposes the same items as serde_json, just with different error types. For more detailed documentation see serde_json.

Migrating from serde_json

To enrich your errors simply replace your dependency on serde_json with one on serde_json_path_to_error.

- serde_json = "1.0"
+ serde_json = { package = "serde_json_path_to_error", version = "0.1" }

Alternatively, you can add serde_json_path_to_error as a regular dependancy...

# cargo add serde_json_path_to_error 

..and rename the crate in your crate root to get the same API as serde_json.

extern crate serde_json_path_to_error as serde_json;

In most cases, your project should continue to compile after migrating. Your errors will now be enriched with additional context showing the path to serialization and deserialization failures.

// the rename trick shown above
extern crate serde_json_path_to_error as serde_json;

# use std::collections::BTreeMap as Map;
# use serde::Deserialize;
#[derive(Deserialize)]
struct Package {
    name: String,
    dependencies: Map<String, Dependency>,
}

#[derive(Deserialize)]
struct Dependency {
    version: String,
}

fn main() {
    let j = r#"{
        "name": "demo",
        "dependencies": {
            "serde": {
                "version": 1
            }
        }
    }"#;


    // Uses the enriched version from [serde_json_path_to_error] but with the exact same API
    // you've come to expect from [serde_json]
    let result: Result<Package, _> = serde_json::from_str(j);

    match result {
        Ok(_) => panic!("expected a type error"),
        Err(err) => {
            // You get the error including the path as a default
            assert_eq!(
              err.to_string(),
              "dependencies.serde.version: invalid type: integer `1`, expected a string at line 5 column 28",
            );
            // You can get just the path
            assert_eq!(
              err.path().to_string(),
              "dependencies.serde.version",
            );
            // Or just the original serde_json error
            assert_eq!(
              err.into_inner().to_string(),
              "invalid type: integer `1`, expected a string at line 5 column 28",
            );
        }
    }
}

Caveats

There are still a small number of items that don't return enriched errors. I'd be interested in accepting PRs that wrap these items.

Dependencies

~0.4–0.8MB
~19K SLoC