Get json value from byte using rust

Viewed 1839

I need to get the name from a base64 value, I tried like following but I didn't able to parse it and get the name property, any idea how can I do it ?

extern crate base64;
use serde_json::Value;
fn main() {


    let v = "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ";

    let bytes = base64::decode(v).unwrap();
    println!("{:?}", bytes);
   
   
    let v: Value = serde_json::from_slice(bytes);
    

}

The value represnt json like

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=1df0f644a139f8d526a44af8abf78e8e

At the end I need to print "name": "John Doe"

this is the decoded value

enter image description here

2 Answers

Denys has provided for the usual way to use serde, and you should definitely apply their solution if that's an option (if the document is not dynamic).

However:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=1df0f644a139f8d526a44af8abf78e8e

Have you considered at least following the indications of the compiler? The Rust compiler is both pretty expressive and very strict, if you give up at every compilation error without even trying to understand what's happenig, you'll have a very hard time.

If you try to compile your snippet, the first thing it tells you is

error[E0308]: mismatched types
  --> src/main.rs:12:43
   |
12 |     let v: Value = serde_json::from_slice(bytes);
   |                                           ^^^^^
   |                                           |
   |                                           expected `&[u8]`, found struct `Vec`
   |                                           help: consider borrowing here: `&bytes`
   |
   = note: expected reference `&[u8]`
                 found struct `Vec<u8>`

and while it doesn't always work out perfectly, the compiler's suggestion is spot-on: base64 has to allocate space for the return value so it yields a Vec, but serde_json doesn't really care where the data comes from so it takes a slice. Just referencing the vec allows rustc to coerce it to a slice.

The second suggestion is:

error[E0308]: mismatched types
  --> src/main.rs:12:20
   |
12 |     let v: Value = serde_json::from_slice(bytes);
   |            -----   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Value`, found enum `Result`
   |            |
   |            expected due to this
   |
   = note: expected enum `Value`
              found enum `Result<_, serde_json::Error>`

which doesn't provide a solution but a simple unwrap would do for testing.

That yields a proper serde_json::value::Value, which you can manipulate the normal way e.g.

v.get("name").and_then(Value::as_str));

will return an Option<&str> of value None if the key is missing or not mapping to a string, and Some(s) if the key is present and mapping to a string: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=5025d399644694b4b651c4ff1b9125a1

Masklinn explains why you have an error, and you should read his answer.

But IMO the simplest and safest solution is to use serde's derive to decode into the desired structure:

use serde::Deserialize;

/// a struct into which to decode the thing
#[derive(Deserialize)]
struct Thing {
    name: String,
    // add the other fields if you need them
}

fn main() {
    let v = "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ";
    let bytes = base64::decode(v).unwrap(); // you should handle errors
    let thing: Thing = serde_json::from_slice(&bytes).unwrap();
    let name = thing.name;
    dbg!(name);
}
Related