1

I try to create a JSON object with serde_json::json! but the problem is that I get \" but I don't want them. How can I prevent or remove them?

fn create_cache_json(token: &str, change: &str, payload: Vec<Value>) -> Value {
   let json = serde_json::json!(
       {
           "token": token,  
           "change": change, 
           "data": {
               "payload": payload
           }
       });
   
   
   info!("{}", json);

   return json;
}

this code returns

{
   "change": "\"new\"",
   "data": {
       "payload":[]
   },
   "token": "\"2a256356\""
}

EDIT: The input values are:

fn main() {
    let token: &str = "foo".to_string();
    let change: &str = "new".to_string();
    let payload: Vec<serde_json::Value> = Vec::new();
 
    create_cache_json(token, change, payload);
}

The input are literals that already have quotes.

The token output is: "foo" but it should be foo. Using crates like quote don't work because the values have to be strings. For this function should the payload be empty.

Jan
  • 93
  • 9
  • 1
    Please provide values for `change` and `token` -- which are necessary to make your code a [mre] (the shortest possible thing we can run with no changes or additions and see the same result) anyhow. The obvious interpretation of this behavior is that you're assigning values that contain literal quotes as part of the value itself (perhaps because the value was encoded as JSON separately before being added to a JSON document), and the easy answer given that interpretation is _don't do that_; the literal text of the `change` variable should just be `new`, not `"new"`. – Charles Duffy Feb 24 '23 at 16:57
  • I'm not really sure what you mean because there are values for `change` and `token`. I can't create the literal because I build the string from `Option<&serde_json::Value>.map(|s| s.to_string()).unwrap();`. – Jan Feb 27 '23 at 05:48
  • You're giving us the _output_ values but not the _input_ values, and the input values are the problem (insofar as they contain literal quotes as part of the data). [Edit] the question to include a [MRE] that goes into how the input values are generated and then we'll have what we need to answer this question correctly. – Charles Duffy Feb 27 '23 at 13:54
  • The above comment is helpful, but enough information to answer a question should be included _in the question itself_, a definition that comments don't count towards. – Charles Duffy Feb 27 '23 at 13:57
  • 1
    Instead of using `to_string()`, to retrieve your original string values, use [`as_str()`](https://docs.rs/serde_json/1.0.93/src/serde_json/value/mod.rs.html#491-496) and you'll get the original string, not a JSON escaping of it. – Charles Duffy Feb 27 '23 at 14:22

1 Answers1

0

I fixed it by changing the json! function to format! and then creating a Value from the String.

Here is the code to create a JSON object with given arguments. This should work with every datatype. If anyone else need this:

fn create_json(
     token: String, 
     change: String, 
     payload: Vec<Value>
) -> CacheEntry {

    let body: String = format!(
        "{{\"token\": {token}, \"change\": {change}, \"data\": [{:#?}] }}"
        , payload);
    let json: CacheEntry = serde_json::from_str(&body).unwrap();

    return json;
}

EDIT: As Charles Duffy said, the code above is vulnerable to injection attacks and here is a better solution:

The code from the question was already correct but the input strings are wrong. Instead of using to_string() the input string literal should converted with as.str() like this:

fn main() {
    let token: &str = "foo".as_str();
    let change: &str = "new".as_str();
    let payload: Vec<serde_json::Value> = Vec::new();
 
    create_cache_json(token, change, payload);
}
fn create_cache_json(token: &str, change: &str, payload: Vec<Value>) -> Value {
   let json = serde_json::json!(
       {
           "token": token,  
           "change": change, 
           "data": {
               "payload": payload
           }
       });
   
   
   info!("{}", json);

   return json;
}
Jan
  • 93
  • 9
  • Don't do this: it permits injection attacks, and means that strings that need quoting or escaping to become valid JSON won't get it. – Charles Duffy Feb 27 '23 at 13:54
  • (Or rather: Don't do this unless you're completely certain that all your values are pre-escaped, as `token` and `change` are here; far better practice, though, is to handle your values in literal form and escape everything at once instead of manually track what is and isn't) – Charles Duffy Feb 27 '23 at 14:21
  • Can you give me a short example? - In my understanding I have to avoid quotes if I call a function that adds quotes no matter if there are already quotes around the string literal. – Jan Feb 28 '23 at 09:04
  • Right, but the only reason there are already quotes is because you used `to_string()` instead of `as_string()` to _get_ the values earlier. If you'd used `as_string()` _there wouldn't be quotes added to the original values to start with_, so using `json!` would be correct. – Charles Duffy Feb 28 '23 at 12:37
  • If you can edit the question to provide a [mre] that's doing the `to_string()` parts, then I'll be in a position to add an answer demonstrating. – Charles Duffy Feb 28 '23 at 12:38
  • You mean something like this? [Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=523c8e1700bcabdca9779e1751f777a3) – Jan Mar 01 '23 at 05:53
  • I fixed it with `as_str()` which means I don't need an example. Thanks for the help! – Jan Mar 01 '23 at 13:55
  • Great! Maybe update the question/answer pair so as to point others at the same solution? – Charles Duffy Mar 01 '23 at 16:04
  • @CharlesDuffy I don't know why but this example didn't work anymore. I changed nothing. [Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=6463deb9baf2271c2bcf7e5b5a9bdfcd) – Jan Jul 13 '23 at 13:16