2

I'm trying to create a backend using the Rocket crate:

fn main() {
    rocket::ignite().mount("/", routes![helloPost]).launch();
}

#[derive(Debug, PartialEq, Eq, RustcEncodable, FromForm)]
struct User {
    id: i64,
    USR_Email: String,
    USR_Password: String,
    USR_Enabled: i32,
    USR_MAC_Address: String
}

#[post("/", data = "<user_input>")]
fn helloPost(user_input: Form<User>) -> String {
    println!("print test {}", user_input);
}

When I run cargo run everything works but, when I send a POST request with postman for testing, I get this error:

POST /:
    => Matched: POST / (helloPost)
    => Warning: Form data does not have form content type.
    => Outcome: Forward
    => Error: No matching routes for POST /.
    => Warning: Responding with 404 Not Found catcher.
    => Response succeeded.

I've set the header content type to JSON and with other languages that works, but with Rocket I can't get it to work.

This is my JSON body:

{
    "USR_Email": "test@test.it",
    "USR_Password": "500rockets",
    "USR_Enabled": 0,
    "USR_MAC_Address": "test test"
}

How can fix this?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Mr. Developer
  • 3,295
  • 7
  • 43
  • 110
  • 2
    `Form` is for html forms (e.g. `application/x-www-form-urlencoded`). Try [Json](https://api.rocket.rs/v0.4/rocket_contrib/json/struct.Json.html) from `rocket_contrib` instead. – justinas Jan 29 '20 at 10:07
  • @justinas i've tried but also with dependencie i'm not found Json typing by rocket_contrib -> maybe a missing crate `rocket_contrib`, but i've added on cargo.toml – Mr. Developer Jan 29 '20 at 10:11
  • Just wrote a proper answer, check it out. – justinas Jan 29 '20 at 12:44

1 Answers1

7

Adapted basically verbatim from the rocket_contrib example.

Cargo.toml:

<snip>

[dependencies]
rocket = "0.4.2"
rocket_contrib = "0.4.2"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

src/main.rs:

#![feature(proc_macro_hygiene, decl_macro)]

#[macro_use] extern crate rocket;
use rocket_contrib::json::Json;
use serde::Deserialize;

#[derive(Debug, PartialEq, Eq, Deserialize)]
struct User {
    id: i64,
    USR_Email: String,
    USR_Password: String,
    USR_Enabled: i32,
    USR_MAC_Address: String
}

#[post("/", format = "json", data = "<user_input>")]
fn helloPost(user_input: Json<User>) -> String {
    format!("print test {:?}", user_input)
}

fn main() {
    rocket::ignite().mount("/hello", routes![helloPost]).launch();
}

A few things of note:

  • Use Json instead of Form
  • Add format = "json" to your route
  • Use Deserialize from serde instead of RustcEncodable. Serde has long overtaken rustc_serialize as the serialization solution for Rust and it's what rocket_contrib utilizes.

Testing with curl:

$ curl -H 'Content-Type: application/json' \
    --data '{"id": 123, "USR_Email": "abc@example.com", "USR_Password": "hunter2", "USR_Enabled": 1, "USR_MAC_Address": "ff:ff"}' \
    http://localhost:8000/hello
print test Json(User { id: 123, USR_Email: "abc@example.com", USR_Password: "hunter2", USR_Enabled: 1, USR_MAC_Address: "ff:ff" })

Note that every field in your User has to be present in JSON, or 400 Bad Request will be raised. You might want to use Option<> for some of these.

justinas
  • 6,287
  • 3
  • 26
  • 36
  • 2
    For future viewers, please note that Json is now part of the main rocket crate as of 0.5. – Jose A Jan 23 '22 at 05:45