Error while rocket implementation for creating a basic API - rust

I have been programming in Rust for a month or so and now I wanted to try out API's using Rocket in rust. I tried to implement the below code but I got the error the trait bound \Json<Test>: Responder<'_, '_> is not satisfied . Not quite sure what I did wrong I tried to find out a reason for it but couldn't get any. I am referring to this video and this guide, according to which I did everything correct.
Also side note: I use extern crate rocket but it still does not recognize Build, routes, etc. Any solution to this as well?
#![feature(proc_macro_hygiene, decl_macro)]
#[macro_use]
extern crate rocket;
use rocket::*;
use rocket_contrib::json::Json;
use serde_json::json;
struct Test{
name: String,
}
#[get("/")]
fn hello_world() -> Json<Test> {
let test: Test = Test { name: String::from("Test54") };
Json(test)
}
#[launch]
fn rocket() -> Rocket<Build> {
rocket::build()
.mount(
"/",
routes![hello_world]
)
}
cargo.toml
[package]
name = "backend"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
name = "lib"
path = "src/lib.rs"
[[bin]]
name = "backend"
path = "src/bin.rs"
[dependencies]
rocket = "0.5.0-rc.1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
[dependencies.rocket_contrib]
version = "0.4"
default-features = false
features = ["json"]
error log
error[E0277]: the trait bound `Json<Test>: Responder<'_, '_>` is not satisfied
--> src/bin.rs:19:21
|
19 | fn hello_world() -> Json<Test> {
| ^^^^^^^^^^ the trait `Responder<'_, '_>` is not implemented for `Json<Test>`
|
= help: the following other types implement trait `Responder<'r, 'o>`:
<&'o [u8] as Responder<'r, 'o>>
<&'o str as Responder<'r, 'o>>
<() as Responder<'r, 'static>>
<(ContentType, R) as Responder<'r, 'o>>
<(Status, R) as Responder<'r, 'o>>
188 | pub fn from<R: Responder<'r, 'o>>(req: &'r Request<'_>, responder: R) -> Outcome<'r> {
| ^^^^^^^^^^^^^^^^^ required by this bound in `route::handler::<impl Outcome<rocket::Response<'o>, Status, rocket::Data<'o>>>::fr
om`
For more information about this error, try `rustc --explain E0277`.

rocket_contrib::json::Json only implements rocket::response::Responder if the T it contains implements serde::ser::Serialize (due to this). Currently, your Teststruct does not implement Serialize, so Json<Test> does not implement Responder; this is what the compiler is complaining about.
You can easily implement Serialize for Test by deriving it:
use serde::Serialize;
#[derive(Serialize)]
struct Test {
name: String,
}

Related

Error on Post Method query_builder::QueryFragment / query_builder::QueryFragment

I am relatively new to rust and have really enjoyed playing around with it. However I am stuck on an error for my CRUD application using Diesel and Rocket. I have a main.rs, model.rs and schema.rs.
I get an error with my POST method that uses the User struct i created.
I am using a postgres DB i have running in the background on docker, Diesel and rocket for routing.
My models.rs
use super::schema::users;
use diesel::{prelude::*, table, Queryable, Insertable, RunQueryDsl};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Queryable, Debug, Insertable)]
#[table_name= "users"]
pub struct User {
pub id: i32,
pub first_name: String,
pub last_name: String,
pub user_name: String,
pub email_address: String,
}
My main.rs (included everything for detail but really question is about the Post method - create_user
#[macro_use] extern crate rocket;
mod models;
mod schema;
use rocket_sync_db_pools::{database};
use models::{User};
use rocket::{serde::json::Json};
use diesel::{RunQueryDsl};
use schema::users;
#[database("my_db")]
pub struct Db(rocket_sync_db_pools::diesel::PgConnection);
#[get("/")]
fn index() -> &'static str {
"Hello World"
}
#[get("/<id>")]
fn get_user(id: i32) -> Json<User> {
Json(User {
id: id,
first_name: "A Fist Name".to_string(),
last_name: "A Last Name".to_string(),
user_name: "A User Name".to_string(),
email_address: "AnEmail#email.com".to_string(),
})
}
#[post("/", data = "<user>")]
async fn create_user(connection: Db, user: Json<User>) -> Json<User> {
connection.run(move |c| {
diesel::insert_into(users::table)
.values(&user.into_inner())
.get_result(c)
})
.await
.map(Json)
.expect("There was an error saving the user")
}
#[launch]
fn rocket() -> _ {
let rocket = rocket::build();
rocket
.attach(Db::fairing())
.mount("/", routes![index])
.mount("/users", routes![get_user, create_user])
}
Dependencies from Cargo.toml
[dependencies]
diesel = "2.0.2"
diesel_cli = { version = "1.4.1", default-features = false, features = ["postgres"] }
rocket = { version = "0.5.0-rc.2", features = ["json"] }
rocket_sync_db_pools = { version = "0.1.0-rc.2", features = ["diesel_postgres_pool"] }
serde = "1.0.140"
The error message
--> src/main.rs:66:6
|
66 | .get_result(c)
| ^^^^^^^^^^
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`with_auth_rust_rocket_diesel_binary`)
= note: required because of the requirements on the impl of `diesel::query_builder::QueryFragment<_>` for `DefaultableColumnInsertValue<diesel::insertable::ColumnInsertValue<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, &i32>>>`
= note: 123 redundant requirements hidden
= note: required because of the requirements on the impl of `diesel::query_builder::QueryFragment<_>` for `DefaultableColumnInsertValue<diesel::insertable::ColumnInsertValue<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, &i32>>>`
= note: required because of the requirements on the impl of `diesel::insertable::InsertValues<table, _>` for `DefaultableColumnInsertValue<diesel::insertable::ColumnInsertValue<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, &i32>>>`
= note: 3 redundant requirements hidden
= note: required because of the requirements on the impl of `diesel::query_builder::QueryFragment<_>` for `diesel::query_builder::InsertStatement<table, diesel::query_builder::insert_statement::ValuesClause<(DefaultableColumnInsertValue<diesel::insertable::ColumnInsertValue<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, &i32>>>, DefaultableColumnInsertValue<diesel::insertable::ColumnInsertValue<columns::first_name, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>, DefaultableColumnInsertValue<diesel::insertable::ColumnInsertValue<columns::last_name, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>, DefaultableColumnInsertValue<diesel::insertable::ColumnInsertValue<columns::user_name, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>, DefaultableColumnInsertValue<diesel::insertable::ColumnInsertValue<columns::email_address, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>), table>, diesel::query_builder::insert_statement::private::Insert, diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::first_name, columns::last_name, columns::user_name, columns::email_address)>>`
= note: required because of the requirements on the impl of `diesel::query_dsl::LoadQuery<'_, _, _>` for `diesel::query_builder::InsertStatement<table, diesel::query_builder::insert_statement::ValuesClause<(DefaultableColumnInsertValue<diesel::insertable::ColumnInsertValue<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, &i32>>>, DefaultableColumnInsertValue<diesel::insertable::ColumnInsertValue<columns::first_name, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>, DefaultableColumnInsertValue<diesel::insertable::ColumnInsertValue<columns::last_name, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>, DefaultableColumnInsertValue<diesel::insertable::ColumnInsertValue<columns::user_name, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>, DefaultableColumnInsertValue<diesel::insertable::ColumnInsertValue<columns::email_address, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>), table>>`
note: required by a bound in `diesel::RunQueryDsl::get_result`
--> /Users/me/.cargo/registry/src/github.com-1ecc6299db9ec823/diesel-2.0.2/src/query_dsl/mod.rs:1679:15
|
1679 | Self: LoadQuery<'query, Conn, U>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `diesel::RunQueryDsl::get_result`
I have reviewed both Diesel, Rocket and Rust documentation and worked worked through other examples for what I can find online however still do not quite get what i am doing incorrectly. Thanks in advance for any help.
I tried to create a post method that uses Diesel to take a Json version of my User object and insert it into my database.
This is a mismatch between the diesel version used by your project (2.0.2) and the diesel version provided by rocket_sync_db_pools (1.4.8). This means the c in connection.run(move |c| { is just a completely different type than expected by get_result, even if the types share the same name.

Compiler Unaware of Provided Methods of Trait

I'm using the prost crate in a very "hello world" way, with a basic ProtoBuf file:
foo.proto
syntax = "proto3";
package foo;
message Foo {
string mystring = 1;
}
I can verify the types that prost produces at compile time by inspecting ./target/PROJECT/build/PROJECT-{some hash}/out/foo.rs:
foo.rs
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Foo {
#[prost(string, tag="1")]
pub mystring: ::prost::alloc::string::String,
}
See that the prost::Message trait gets derived? Its docs claim I have tons of functions at my disposal for this trait, but only the two required ones, encoded_len() and clear(), can be called without error. Any of the provided ones (those with default implementations) result in a cannot find function in this scope error.
main.rs
use prost::Message;
pub mod foo {
include!(concat!(env!("OUT_DIR"), "/foo.rs"));
}
fn main() {
let f = foo::Foo { mystring: "bar".to_string() };
let v = encode_to_vec(&f);
}
cargo run
error[E0425]: cannot find function `encode_to_vec` in this scope
|
| let v = encode_to_vec(&f);
| ^^^^^^^^^^^^^ not found in this scope
And, worryingly, this warning implies it's not even looking at the trait it needs to:
warning: unused import: prost::Message
(edit) For reference:
Cargo.toml
[package]
name = "testing"
version = "0.1.0"
edition = "2018"
[dependencies]
prost = { version = "0.7.0", features = ["std"] }
[build-dependencies]
prost-build = "0.7.0"
encode_to_vec is not a free function. You need to call it as one of
f.encode_to_vec()
foo::Foo::encode_to_vec(&f)
Message::encode_to_vec(&f)
<foo::Foo as Message>::encode_to_vec(&f)
The first method is the most normal, but the other ones may produce useful error messages when you get confused about what's going on.
[Edit:] Well, encode_to_vec was added in prost 0.8.0, so with 0.7.0, it won't be usable.

Rust trait not satisfied

I'm new to rust and tried searching in stackoverflow as well as reading the serde documentation
https://docs.serde.rs/serde/trait.Serialize.html and https://serde.rs/impl-serialize.html, but I was a bit lost.
I would like to use Tera to generate html and the struct I'm passing it does not have the trait serde::ser::Serialize implemented and I tried to implement it but it doesn't appear quite right.
Cargo.toml dependencies
serde = "1.0.115"
serde_derive = "1.0.115"
serde-xml-rs = "0.4.0"
tera = "0.7.2"
main.rs
extern crate tera;
#[macro_use]
extern crate serde_derive;
extern crate serde;
use tera::Context;
use serde::ser::{Serialize, SerializeStruct, Serializer};
#[derive(Serialize, Debug)]
struct Person {
firstname: String,
lastname: String,
age: i32,
}
#[derive(Debug)]
struct Attendees {
people: Vec<Person>,
updatedOn: String,
updatedBy: String,
}
impl Serialize for Attendees {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut s = serializer.serialize_struct("Person", 3)?;
s.serialize_field("people", &self.people)?;
s.serialize_field("updatedOn", &self.updatedOn)?;
s.serialize_field("updatedBy", &self.updatedBy)?;
s.end()
}
}
fn main() {
let mut context = Context::new();
let mut peeps: Vec<Person> = Vec::new();
let mut attendees = Attendees {
people: peeps,
updatedOn: String::from("today"),
updatedBy: String::from("someone"),
};
context.add("attendees", &attendees);
}
compiler says:
mytest % cargo run
Compiling mytest v0.1.0 (/home/mike/mytest)
error[E0277]: the trait bound `Attendees: serde::ser::Serialize` is not satisfied
--> src/main.rs:44:29
|
44 | context.add("attendees", &attendees);
| ^^^^^^^^^^ the trait `serde::ser::Serialize` is not implemented for `Attendees`
error: aborting due to previous error
I am clearly missing something... Can anyone please help?
The trait you implemented and the trait that the error is referring are not the same, because they refer to two different versions of serde.
[[package]]
name = "tera"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c37e2aaa53871f9c3722a20f8951fea0afd366955e11542a58feb71997c6d769"
dependencies = [
"chrono",
"error-chain",
"glob",
"humansize",
"lazy_static 0.2.11",
"pest",
"regex",
"serde 0.9.15",
"serde_json",
"slug",
"url",
]
tera 0.7.2 is not using the version 1.0.* of serde, but 0.9.*.
You may use a more recent of tera, or use a compatible serde version in your Cargo.toml:
[dependencies]
serde = "0.9.15"
serde_derive = "0.9.15"

Handlebars helpers within Rocket

I am trying to register a helper for handlebars the ultimate goal is to be able to have a helper that calculates/prints the length of a Vec. But I already fail to get the samples from the documentation into my program. I managed to do a 'minimal' example that shows the same error as my rocket page.
#[macro_use]
extern crate handlebars;
extern crate rocket;
extern crate rocket_contrib;
use handlebars::{Context, Handlebars, Helper, HelperResult, JsonRender, Output, RenderContext};
use rocket_contrib::templates::Template;
handlebars_helper!(hex: |v: i64| format!("0x{:x}", v));
fn wow_helper(
h: &Helper,
_: &Handlebars,
_: &Context,
_: &mut RenderContext,
out: &mut Output,
) -> HelperResult {
if let Some(param) = h.param(0) {
out.write("<b><i>")?;
out.write(&param.value().render())?;
out.write("</b></i>")?;
}
Ok(())
}
fn main() {
rocket::ignite()
.attach(Template::custom(|engines| {
engines
.handlebars
.register_helper("mlenb", Box::new(wow_helper));
}))
.launch();
println!("Hello, world!");
}
with the dependencies in cargo.toml:
[dependencies]
handlebars="3.3.0"
rocket="0.4.5"
[dependencies.rocket_contrib]
version = "0.4.5"
default-features = false
features = ["diesel_sqlite_pool", "handlebars_templates", "serve"]
The error:
error[E0631]: type mismatch in function arguments
--> src/main.rs:184:43
|
162 | / fn wow_helper(
163 | | h: &handlebars::Helper,
164 | | _: &handlebars::Handlebars,
165 | | _: &handlebars::Context,
... |
175 | | Ok(())
176 | | }
| |_- found signature of `for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7> fn(&'r handlebars::Helper<'s, 't0>, &'t1 handlebars::Handlebars<'t2>, &'t3 handlebars::Context, &'t4 mut handlebars::RenderContext<'t5, 't6>, &'t7 mut (dyn handlebars::Output + 't7)) -> _`
...
184 | .register_helper("mlenb", Box::new(wow_helper));
| ^^^^^^^^^^^^^^^^^^^^ expected signature of `for<'r, 'reg, 'rc, 's, 't0> fn(&'r rocket_contrib::templates::handlebars::Helper<'reg, 'rc>, &'reg rocket_contrib::templates::handlebars::Handlebars, &'rc rocket_contrib::templates::handlebars::Context, &'s mut rocket_contrib::templates::handlebars::RenderContext<'reg>, &'t0 mut (dyn rocket_contrib::templates::handlebars::Output + 't0)) -> _`
|
= note: required because of the requirements on the impl of `rocket_contrib::templates::handlebars::HelperDef` for `for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7> fn(&'r handlebars::Helper<'s, 't0>, &'t1 handlebars::Handlebars<'t2>, &'t3 handlebars::Context, &'t4 mut handlebars::RenderContext<'t5, 't6>, &'t7 mut (dyn handlebars::Output + 't7)) -> std::result::Result<(), handlebars::RenderError> {wow_helper}`
= note: required for the cast to the object type `dyn rocket_contrib::templates::handlebars::HelperDef`
Don't need to use crate handlebars in cargo.toml with rocket crate.
its works well like that:
in cargo.toml only
[dependencies]
rocket = "0.4.5"
[dependencies.rocket_contrib]
version = "0.4.5"
default-features = false
features = ["handlebars_templates", "serves"]
and in the main.rs use:
use rocket_contrib :: templates :: {Template, handlebars};
use handlebars :: {Helper, Handlebars, Context, RenderContext, Output, HelperResult, RenderError};
So there will be no problems with versioning the handlebars!
Thanks to #jebrosen:mozilla.org in the rocket matrix channel the problem got resolved.
Problem:
I used incompatible versions of handlebars. The rocket library uses version 1.0 while I used Version 3.0 in the Cargo.toml.
Solution:
Change the Cargo.toml to:
[dependencies]
handlebars="1.0"
rocket="0.4.5"
[dependencies.rocket_contrib]
version = "0.4.5"
default-features = false
features = ["diesel_sqlite_pool", "handlebars_templates", "serve"]
Careful a rebuild requires a cargo clean otherwise the changes don't get built.
Solution for the initial Problem:
I did not manage to use the macro handlebars_helper! to create the length helper but instead created it using the function syntax.
fn mlen_helper_fun(
h: &handlebars::Helper<'_, '_>,
_: &handlebars::Handlebars,
_: &handlebars::Context,
_: &mut handlebars::RenderContext<'_>,
out: &mut dyn handlebars::Output,
) -> handlebars::HelperResult {
if let Some(param) = h.param(0) {
if let serde_json::value::Value::Array(arr) = param.value() {
out.write(&format!("{}", arr.len()))?;
Ok(())
} else {
Err(handlebars::RenderError::new("Not a array"))
}
} else {
Err(handlebars::RenderError::new(
"No parameter given at least one required",
))
}
}
This can then be used with:
.attach(Template::custom(|engines| {
engines
.handlebars
.register_helper("length", Box::new(mlen_helper_fun));
}))

the trait `serde::Deserialize<'_>` is not implemented for `diesel_geography::types::GeogPoint`

I'm trying to use Diesel and diesel_geography to read from a PostGIS database using Rust.
Here's the error I'm getting:
error[E0277]: the trait bound `diesel_geography::types::GeogPoint: serde::Serialize` is not satisfied
--> src/models.rs:11:5
|
11 | pub coordinates: GeogPoint,
| ^^^ the trait `serde::Serialize` is not implemented for `diesel_geography::types::GeogPoint`
|
= note: required by `serde::ser::SerializeStruct::serialize_field`
error[E0277]: the trait bound `diesel_geography::types::GeogPoint: serde::Deserialize<'_>` is not satisfied
--> src/models.rs:11:5
|
11 | pub coordinates: GeogPoint,
| ^^^ the trait `serde::Deserialize<'_>` is not implemented for `diesel_geography::types::GeogPoint`
|
= note: required by `serde::de::SeqAccess::next_element`
error[E0277]: the trait bound `diesel_geography::types::GeogPoint: serde::Deserialize<'_>` is not satisfied
--> src/models.rs:11:5
|
11 | pub coordinates: GeogPoint,
| ^^^ the trait `serde::Deserialize<'_>` is not implemented for `diesel_geography::types::GeogPoint`
|
= note: required by `serde::de::MapAccess::next_value`
Looking around, I found that a similar error happens when there are several versions of serde used as dependency, this can be checked using cargo tree -d. I've tried and serde does not appear as a duplicate dependency.
This is my code so far:
Cargo.toml
[package]
name = "123"
version = "0.1.0"
authors = ["ASD"]
edition = "2018"
[dependencies]
diesel = { version = "1.4.2", features = ["postgres"] }
serde = { version = "1.0", features = ["derive"] }
serde_json="1.0"
dotenv = "0.14.1"
diesel-geography = "0.2.0"
schema.rs
table! {
use diesel::sql_types::*;
use diesel_geography::sql_types::*;
users (email) {
email -> Varchar,
password -> Varchar,
coordinates -> Geography
}
}
models.rs
use diesel_geography::types::*;
use crate::schema::users;
use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize, Queryable, Insertable)]
#[table_name = "users"]
pub struct User {
pub email: String,
pub password: String,
pub coordinates: GeogPoint
}
main.rs
extern crate serde;
extern crate dotenv;
#[macro_use] extern crate diesel;
//#[macro_use] extern crate serde_derive;
mod models;
mod schema;
use diesel::PgConnection;
use dotenv::dotenv;
use std::env;
use diesel::prelude::*;
fn main() {
dotenv().ok();
let database_url = env::var("DATABASE_URL")
.expect("DATABASE_URL must be set");
let connection = PgConnection::establish(&database_url)
.expect(&format!("Error connecting to {}", database_url));
use crate::schema::users::dsl::*;
use crate::models::User;
let results = users
.limit(5)
.load::<User>(&connection)
.expect("Error loading users");
println!("Displaying {} users", results.len());
for user in results {
println!("{}", user.email);
println!("----------\n");
println!("{}", user.password);
}
}
Serde is an optional dependency of diesel-geography. You need to enable the feature:
[dependencies]
diesel-geography = { version = "0.2.0", features = ["serde"] }

Resources