Issue trying to set up Rocket server with a Mongodb pool - rust

I'm switching from Nodejs with NestJs to Rust Rocket + juniper. Even if I start feeling confident in Rust i'm having difficulties with some simple thing.
I'm trying to create a mongdb pool to attach to my app but I'm having some issue. Here is my main function:
#![feature(proc_macro_hygiene, decl_macro)]
#[macro_use] extern crate rocket;
#[macro_use] extern crate rocket_contrib;
#[rocket_contrib::database("db")]
struct DatabaseConnection(rocket_contrib::databases::mongodb::db::Database);
// mod features;
#[rocket::main]
async fn main() {
rocket::build()
.attach(DatabaseConnection::fairing())
.mount(
"/",
rocket::routes![],
)
.launch()
.await
.expect("server to launch");
}
And here is my cargo.toml file:
[package]
name = "rocket_graphql"
version = "0.1.0"
edition = "2018"
[dependencies]
rocket = "0.5.0-rc.1"
juniper = { git = "https://github.com/graphql-rust/juniper" }
juniper_rocket = "0.2.0"
mongodb = "2.0.0-beta.2"
bson = "1.2.1"
tokio = { version = "1.8.0", features = ["full"] }
[dependencies.rocket_contrib]
version = "0.4.10"
default-features = false
features = ["mongodb_pool"]
[global.databases]
db = {url = "my-mongo-atlas-instance-url"}
I'm getting an error on this line #[rocket_contrib::database("db")]
it says: unresolved import 'rocket' no 'Outcome' in the root.
Can you please tell me what I'm doing wrong here?
Thank you very much

I'm using Rocket 0.5. According to the changelog, the rocket_contrib has been deprecated in favor for rocket_sync_db_pools which doesn't seem to cover mongodb yet. So what I did is to create a state struct to hold a reference to the database. So thanks to the manage method on rocket, the reference to the database can be passed to all the routes. Feel free to correct it if I did anything wrong
I ended up doing this:
#![feature(proc_macro_hygiene, decl_macro)]
use mongodb::{
Client, Database,
};
use rocket::{self, get, State};
#[get("/")]
async fn index(mongo_db: &State<AppDataPool>) -> &'static str {
for coll_name in mongo_db.mongo.list_collection_names(None).await {
println!("collection: {:?}", coll_name);
}
"helloooo"
}
struct AppDataPool {
mongo: Database,
}
#[rocket::main]
async fn main() {
let client = Client::with_uri_str("----").await;
let db = client.unwrap().database("my-db");
for coll_name in db.list_collection_names(None).await {
println!("collection: {:?}", coll_name);
}
rocket::build()
.manage(AppDataPool { mongo: db })
.mount("/", rocket::routes![index])
.launch()
.await
.expect("server to launch");
}

Related

Why get method is not returning a Response object in reqwest?

I'm trying to replicate an example from reqwest documentation. Here is the example:
let body = reqwest::get("https://www.rust-lang.org")?
.text()?;
After I have added the reqwest = "0.10.10" line in the file Cargo.toml, I add the following code in my main.rs file:
extern crate reqwest;
fn main() {
let body = reqwest::get("https://www.rust-lang.org")?.text()?;
println!("body = {:?}", body);
}
This code don't compile and returns the following error:
cannot use the `?` operator in a function that returns `()`
I'm a bit surprised with this behaviour since my code is almost ipsis litteris the documentation code.
I think that ? works only on Response objects, so I checked which object the get method is returning:
extern crate reqwest;
fn print_type_of<T>(_: &T) {
println!("{}", std::any::type_name::<T>())
}
fn main() {
let body = reqwest::get("https://www.rust-lang.org");
print_type_of(&body);
}
output:
core::future::from_generator::GenFuture<reqwest::get<&str>::{{closure}}
I mean, why I'm not getting an Response object instead, just like the documentation?
There are two separate issues here tripping you up.
The documentation that you've linked to is for reqwest version 0.9.18, but you've installed version 0.10.10. If you look at the docs for 0.10.10, you will see that the snippet you use is
let body = reqwest::get("https://www.rust-lang.org")
.await?
.text()
.await?;
println!("body = {:?}", body);
or more likely in your case, since you have not mentioned having an async runtime, the blocking docs
let body = reqwest::blocking::get("https://www.rust-lang.org")?
.text()?;
println!("body = {:?}", body);
Note that when you try to use this one, you will still get that
cannot use the ? operator in a function that returns ()
and you will need to set a return type on main like
fn main() -> Result<(), reqwest::Error> {
See Why do try!() and ? not compile when used in a function that doesn't return Option or Result? for more info.
You might want to read this section of the Rust docs: https://doc.rust-lang.org/edition-guide/rust-2018/error-handling-and-panics/index.html
In short, ? simply passes the error from a Result further up the call stack via an implicit return. As such the function in which you use the ? operator must return the same type as the function on which ? was used.
Each response is wrapped in a Result type which you can unwrap.
use reqwest;
#[tokio::main]
async fn main() {
let response = reqwest::get("https://www.rust-lang.org")
.await
.unwrap()
.text()
.await;
println!("{:?}", response);
}
Cargo.toml:
[package]
name = "request"
version = "0.1.0"
edition = "2021"
reqwest = "0.10.10"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
reqwest = { version = "0.11", features = ["json"] } # reqwest with JSON parsing support
futures = "0.3" # for our async / await blocks
tokio = { version = "1.12.0", features = ["full"] } # for async runtime

The trait `std::convert::From<cli::Opts>` is not implemented

I try to create a simple application parsing command line arguments using clap library and converting them to a Config custom structure. I implemented From trait for my structure, however, when I try to call from function, I receive the following error:
the trait bound `minimal_example::Config: std::convert::From<cli::Opts>` is not satisfied
the following implementations were found:
<minimal_example::Config as std::convert::From<minimal_example::cli::Opts>>
required by `std::convert::From::from`
Here is the code:
main.rs:
mod cli;
use clap::Clap;
use minimal_example::Config;
fn main() {
println!("Hello, world!");
let opts = cli::Opts::parse();
let config = Config::from(opts);
}
cli.rs:
use clap::{Clap, crate_version};
/// This doc string acts as a help message when the user runs '--help'
/// as do all doc strings on fields
#[derive(Clap)]
#[clap(version = crate_version!(), author = "Yury")]
pub struct Opts {
/// Simple option
pub opt: String,
}
lib.rs:
mod cli;
pub struct Config {
pub opt: String,
}
impl From<cli::Opts> for Config {
fn from(opts: cli::Opts) -> Self {
Config {
opt: opts.opt,
}
}
}
cargo.toml:
[package]
name = "minimal_example"
version = "0.1.0"
authors = ["Yury"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
clap = {version="3.0.0-beta.2", features=["wrap_help"]}
What am I doing wrong?
You have added mod cli to both lib.rs and main.rs.
They are different from the standpoint of each other.
Rust modules confusion when there is main.rs and lib.rs
may help in understanding that.
That's what the error says. It's satisfied for std::convert::From<minimal_example::cli::Opts> but not for std::convert::From<cli::Opts>.
A simple fix:
main.rs
mod cli;
use clap::Clap;
use minimal_example::Config;
impl From<cli::Opts> for Config {
fn from(opts: cli::Opts) -> Self {
Config {
opt: opts.opt,
}
}
}
fn main() {
println!("Hello, world!");
let opts = cli::Opts::parse();
let config = Config::from(opts);
}
Now std::convert::From<cli::Opts> is implemented for Config.
How you actually want to place all this depends on your package architecture.

rust actix: how can I properly return an App instance from a module?

I'd like to return an App instance from a module, but I just don't get anywhere.
I am propably doing everything wrong, that can be done wrong.
Here's my effort so far:
app.rs (called by main.rs)
extern crate actix_web;
extern crate actix_http; // => can't be found
extern crate actix_service; // => can't be found
use actix_web::App;
use actix_http::body::MessageBody;
use actix_service::ServiceFactory;
pub fn create() -> Result<App<MessageBody, ServiceFactory>, Error> {
let app = App::new();
// adding services
Ok(App)
}
There's propably a lot wrong with this code, but at the moment my main problem is that I can't import actix_http and actix_service which both are needed to return the proper types of the App result.
Addendum:
Cargo.toml
[package]
name = "backend"
version = "0.1.0"
authors = ["My Name <my#emai.l>"]
edition = "2018"
[dependencies]
actix-web="3"
diesel= { version = "1.4.5", features = ["mysql"] }
dotenv= { version = "0.15.0" }
[[bin]]
name = "main"
path = "src/main.rs"

How to forward data from a reqwest::blocking::Body in a Rocket responder?

I'm able to request a PNG file with reqwest which I can save to a file through copy().
I'd like to forward the image as a Rocket response. I don't know how to pass the response contents there.
I tried to use Content(ContentType::PNG, response) but I can't figure out how to match a type that has implemented rocket::response::Responder trait. Rocket can't use the Bytes type returned by response.bytes().
#![feature(proc_macro_hygiene, decl_macro)]
extern crate reqwest;
#[macro_use]
extern crate rocket;
use anyhow::Result;
use reqwest::header::USER_AGENT;
use reqwest::Response;
use rocket::http::ContentType;
use rocket::response::content::Content;
#[get("/")]
fn myroute() -> Result<Content<String>, anyhow::Error> {
let client = reqwest::blocking::Client::new();
let response = client.get("https://www.rust-lang.org/static/images/rust-logo-blk.svg")
.header(USER_AGENT, "rust-reqwest")
.send()?;
Ok(Content(ContentType::PNG, response.bytes()))
}
fn rocket() -> rocket::Rocket {
rocket::ignite()
.mount("/", routes![myroute])
}
fn main() {
rocket().launch();
}
[dependencies]
anyhow = "1.0"
rocket = "0.4.2"
reqwest = { version = "0.10.4", features = ["blocking", "json"] }

Can't encode struct into JSON in Rust

I'm following an Iron web framework tutorial, which seemed pretty simple, but I can't seem to encode a struct as JSON.
extern crate iron;
extern crate rustc_serialize;
use iron::prelude::*;
use iron::status;
use rustc_serialize::json;
struct Greeting {
msg: String,
}
fn main() {
fn hello_world(_: &mut Request) -> IronResult<Response> {
let greeting = Greeting { msg: "hello_world".to_string() };
let payload = json::encode(&greeting).unwrap();
// Ok(Response::with((status::Ok,payload)))
}
// Iron::new(hello_world).http("localhost:3000").unwrap();
}
My Cargo.toml
[package]
name = "iron_init"
version = "0.1.0"
authors = ["mazbaig"]
[dependencies]
iron = "*"
rustc-serialize = "*"
And my error:
error: the trait bound `Greeting: rustc_serialize::Encodable` is not satisfied [E0277]
let payload = json::encode(&greeting).unwrap();
^~~~~~~~~~~~
help: run `rustc --explain E0277` to see a detailed explanation
note: required by `rustc_serialize::json::encode`
I kinda get that the right types aren't getting passed into the json.encode() function, but I'm having trouble figuring out what it wants from me. I'm probably missing something really basic.
You didn't provide the actual tutorial that you are using, but it appears to match this one from brson.
extern crate iron;
extern crate rustc_serialize;
use iron::prelude::*;
use iron::status;
use rustc_serialize::json;
#[derive(RustcEncodable)]
struct Greeting {
msg: String
}
fn main() {
fn hello_world(_: &mut Request) -> IronResult<Response> {
let greeting = Greeting { msg: "Hello, World".to_string() };
let payload = json::encode(&greeting).unwrap();
Ok(Response::with((status::Ok, payload)))
}
Iron::new(hello_world).http("localhost:3000").unwrap();
println!("On 3000");
}
Notice anything different between the two?
#[derive(RustcEncodable)]
struct Greeting {
msg: String
}
You have to specify that the Encodable trait is implemented. In this case, you can do so by deriving RustcEncodable.

Resources