Search code examples
shellescapingquoting

why tell the key must be a string when request rust rocket api


I am learning using rust to write a rest api to update some record. I have defined a rust(v1.69.0) rocket api like this:

#[macro_use] extern crate rocket;

use rocket::{serde::json::Json, response::content};
use rust_wheel::common::util::model_convert::box_rest_response;
use rocket::serde::Deserialize;
use rocket::serde::Serialize;

#[put("/test", data = "<request>")]
pub fn flush_render_result(
    request: Json<RenderResultRequest>
) -> content::RawJson<String> {
    let req = request;
    return box_rest_response("ok");
}
#[launch]
fn rocket() -> _ {
    rocket::build().mount("/", routes![flush_render_result])
}

#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
#[allow(non_snake_case)]
pub struct RenderResultRequest {
    pub gen_status: i32,
    pub id: i64,
}

this is the Cargo.toml:

[package]
name = "rust-learn"
version = "0.1.0"
edition = "2018"

[dependencies]
serde = { version = "1.0.64", features = ["derive"] }
serde_json = "1.0.64"
rocket = { version = "0.5.0-rc.2", features = ["json"]}
rust_wheel = { git = "https://github.com/jiangxiaoqiang/rust_wheel.git", branch = "diesel2.0" }

and this is the Rocket.toml:

[release]
workers = 5
log_level = "normal"
keep_alive = 5
port = 11016
[debug]
port = 11016

when I use the command to request the api in macOS 13.2 terminal:

> curl -X PUT http://127.0.0.1:11016/test -H "Content-Type: application/json" -H "x-access-token:1" -H "app-id:1" -H "user-id:1" -H "x-request-id:1" -H "device-id:1" -d "{
    "id": 1,
    "gen_status": 1
}"
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>400 Bad Request</title>
</head>
<body align="center">
    <div role="main" align="center">
        <h1>400: Bad Request</h1>
        <p>The request could not be understood by the server due to malformed syntax.</p>
        <hr />
    </div>
    <div role="contentinfo" align="center">
        <small>Rocket</small>
    </div>
</body>
</html>%

why did this happen? what should I do to fixed this issue? I have already add the "" for keys, why still tell me this error? The server log look like this:

📬 Routes:
   >> (flush_render_result) PUT /test
📡 Fairings:
   >> Shield (liftoff, response, singleton)
🛡️ Shield:
   >> X-Content-Type-Options: nosniff
   >> Permissions-Policy: interest-cohort=()
   >> X-Frame-Options: SAMEORIGIN
🚀 Rocket has launched from http://127.0.0.1:11016
PUT /test application/json:
   >> Matched: (flush_render_result) PUT /test
   >> Data guard `Json < RenderResultRequest >` failed: Parse("{\n    id: 1,\n    gen_status: 1\n}", Error("key must be a string", line: 2, column: 5)).
   >> Outcome: Failure
   >> No 400 catcher registered. Using Rocket default.
   >> Response succeeded.

I have tried to remove the space, still could not work:

curl -X PUT http://127.0.0.1:8000/cv/gen/v1/result -H "Content-Type: application/json" -H "x-access-token:1" -H "app-id:1" -H "user-id:1" -H "x-request-id:1" -H "device-id:1" -d "{"id": 1,"gen_status": 1}"

Solution

  • You failed to properly escape the " in your curl invocation, so the shell consumed them resulting in a payload of

    {
      id: 1,
      gen_status: 1
    }
    

    instead of the valid JSON

    
    {
      "id": 1,
      "gen_status": 1
    }
    

    Note the difference in quoting of the keys.

    to fix it you can invoke curl with escaped quotes (\") inside the json or by using different outer quotes like this:

    curl -X PUT http://127.0.0.1:11016/test [...] -d '{"id": 1, "gen_status": 1}'