4

I'm trying to create a Printing Server in rust and face a problem when trying to send JSON as a response.

I've found on the Rocket documentation that is really easy to send JSON as a response: You just have to use the Serde library.

Unfortunatly, that wasn't so simple for me...

Here is my current code :

#[derive(Serialize,Deserialize)]
pub struct Printers {
    pub printers: Vec<Printer>,
}

#[derive(Serialize,Deserialize)]
pub struct Printer {
    pub device_type: String,
    pub uid: String,
    pub provider: String,
    pub name: String,
    pub connection: String,
    pub version: u8,
    pub manufacturer: String,
}

/**
 * Here is my main problem 
 *   -> I want to send back the Printers Object as a JSON
 */
#[get("/printers")]
fn printers(key: ApiKey<'_>) -> Json<Printers> {
    let resp = crate::get_printers::get();
    Json(resp)
}

Here is the error code :

   --> src/order_route.rs:25:33
    |
25  | fn printers(key: ApiKey<'_>) -> Json<Printers> {
    |                                 ^^^^^^^^^^^^^^ the trait `Responder<'_, '_>` is not implemented for `rocket_contrib::json::Json<order_route::Printers>`
    |
note: required by `route::handler::<impl Outcome<rocket::Response<'o>, Status, rocket::Data<'o>>>::from`
   --> ********/.cargo/registry/src/github.com-1ecc6299db9ec823/rocket-0.5.0-rc.1/src/route/handler.rs:188:5
    |
188 |     pub fn from<R: Responder<'r, 'o>>(req: &'r Request<'_>, responder: R) -> Outcome<'r> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

It seems I need a trait to do this, but don't know how to create it, If someone could help me to find a solution, I will be greatful.

[EDIT]

Here is the Cargo.toml file

[package]
name = "test"
version = "0.0.0"
edition = "2018"
[dependencies]
rocket = "0.5.0-rc.1"
reqwest = { version = "0.11", features = ["blocking", "json"] }
openssl = { version = "0.10", features = ["vendored"] }
json = "0.12.4"
serde = "1.0.127"
serde_json = "1.0.66"

[dependencies.rocket_contrib]
version = "0.4.10"
default-features = false
features = ["json"]

[workspace]
members = [
    ""
]

And here is the full stacktrace

*****:~/*****/label-printer-server-rust/server$ cargo run
   Compiling hello v0.0.0 (/home/*****/*****/label-printer-server-rust/server)
error[E0277]: the trait bound `rocket_contrib::json::Json<order_route::Printers>: Responder<'_, '_>` is not satisfied
   --> src/order_route.rs:25:33
    |
25  | fn printers(key: ApiKey<'_>) -> Json<Printers> {
    |                                 ^^^^^^^^^^^^^^ the trait `Responder<'_, '_>` is not implemented for `rocket_contrib::json::Json<order_route::Printers>`
    |
note: required by `route::handler::<impl Outcome<rocket::Response<'o>, Status, rocket::Data<'o>>>::from`
   --> /home/*****/.cargo/registry/src/github.com-1ecc6299db9ec823/rocket-0.5.0-rc.1/src/route/handler.rs:188:5
    |
188 |     pub fn from<R: Responder<'r, 'o>>(req: &'r Request<'_>, responder: R) -> Outcome<'r> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0308]: mismatched types
  --> src/order_route.rs:27:10
   |
27 |     Json(resp)
   |          ^^^^ expected struct `order_route::Printers`, found enum `Result`
   |
   = note: expected struct `order_route::Printers`
                found enum `Result<structures::Printers, Box<dyn StdError>>`

Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.
error: could not compile `hello` due to 2 previous errors
DirBear
  • 63
  • 1
  • 8

3 Answers3

6

You are using rocket 0.5.0-rc.1 and rocket_contrib 0.4.10. While Json from rocket_contrib does implement Responder, it implements the Responder trait of Rocket v4, not that of Rocket v5.

In Rocket v5, Json is not part of rocket_contib anymore, but included in the rocket crate (note that you need to enable the json feature on the rocket crate):

use rocket::serde::json::Json;
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
pub struct Printers {
    pub printers: Vec<Printer>,
}

#[derive(Serialize, Deserialize)]
pub struct Printer {
    pub device_type: String,
    pub uid: String,
    pub provider: String,
    pub name: String,
    pub connection: String,
    pub version: u8,
    pub manufacturer: String,
}

#[get("/printers")]
fn printers() -> Json<Printers> {
    todo!();
}

Note that you can now also remove rocket_contrib from your Cargo.toml (as you are not using any features from it).

Elias Holzmann
  • 3,216
  • 2
  • 17
  • 33
  • Thanks for your feedback! After checking, I'm not able to find the crate `rocket::serde::json::Json` Maybe I need to update my Cargo.toml? – DirBear Aug 06 '21 at 14:21
  • Have you enabled the `json` feature of `rocket`? – Elias Holzmann Aug 06 '21 at 14:23
  • 1
    I only find how to do this for `rocket_contrib`. Do you have the documentation link where this point is explained, please? – DirBear Aug 06 '21 at 14:25
  • It has to look [like this](https://gist.github.com/bartim/742c1d1c5daeddcd7423e0f4e35d8eea). The cargo book also has more information about [how to enable features in dependencies](https://doc.rust-lang.org/cargo/reference/features.html#dependency-features) as well as about [the layout of `Cargo.toml` in general](https://doc.rust-lang.org/cargo/reference/manifest.html). – Elias Holzmann Aug 06 '21 at 14:32
  • 2
    Thanks again for your feedback, I was searching at the same time and find the specs in Rocket documentation, I left the link here for those who will have the same problem [Link to Rocket documentation for JSON import](https://api.rocket.rs/master/rocket/index.html)! You made my day :D – DirBear Aug 06 '21 at 14:35
6

Anyone who's finding it difficult, here's the solution :

  • Enable JSON feature for rocket rust in your Cargo.toml file

    [package]
    #...
    
    [dependencies.rocket]
    version = "0.5.0-rc.1"
    features = ["json"]
    
    [dependencies.serde]
    version = "1.0.136"
    features = ["derive"]
    
    [dependencies]
    #...
    
    # rocket_contrib not required anymore
    
  • In your src/main.rs file

    // rocket v0.5.0-rc.1
    use rocket::{
       self,
       serde::{json::Json, Deserialize, Serialize},
    };
    
    #[derive(Deserialize, Serialize)]
    struct User {
       name: String,
       age: u8,
    }
    
    #[rocket::post("/post", format = "json", data = "<user>")]
    fn post_data(user: Json<User>) -> Json<User> {
       let name: String = user.name.clone();
       let age: u8 = user.age.clone();
    
       Json(User { name, age })
    }
    
    #[rocket::main]
    async fn main() {
       if let Err(err) = rocket::build()
          .mount("/", rocket::routes![post_data])
          .launch()
          .await
       {
          println!("Rocket Rust couldn't take off successfully!");
          drop(err); // Drop initiates Rocket-formatted panic
       }
    }
    
  • Test API using cURL

    curl -d '{"age": 12,"name":"John Doe"}' -H 'Content-Type: application/json' 
    http://localhost:8000/post
    
    # Response
    # {"name":"John Doe","age":12}
    
0

I wanted to add to Elias' answer, which are mentioned in the comments:

In your cargo.toml you need to enable the JSON feature:

[dependencies]
## SEE HERE!! 
rocket = {version ="0.5.0-rc.1", features=["json"]}

# other properties omitted for brevity 

# You can remove this!! Rocket Contrib doesn't exist in Rocket V0.5 
#[dependencies.rocket_contrib]
#version = "0.4.10"
#default-features = false
#features = ["json"]


Jose A
  • 10,053
  • 11
  • 75
  • 108