This function should return `Result` or `Option` to accept `?`

Hi,
I’m trying to use ? with client with this code:

async fn index(Form(login): Form<Login>)-> Response<String>{
	let client = Client::with_uri_str("mongodb+srv://user:pass@cluster0.um0c2p7.mongodb.net/?retryWrites=true&w=majority").await?;
	let db = client.database("db").collection::<Login>("coll");
	//...
	Ok(Response::builder().status(axum::http::StatusCode::OK)
        .header("Content-Type", "text/html; charset=utf-8")
        .body(tera.render("index", &context).unwrap()).unwrap())
}

But this error appears:

#9 319.5 error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `FromResidual`)
#9 319.5   --> src/main.rs:51:126
#9 319.5 50 |   async fn index(Form(login): Form<Login>)-> Response<String>{
#9 319.5    |  ______________________________________________________________-
#9 319.5 51 | |     let client = Client::with_uri_str("***cluster0.um0c2p7.mongodb.net/?retryWrites=true&w=majority").await?;
#9 319.5    | |                                                                                                                                 ^ cannot use the `?` operator in an async function that returns `Response<std::string::String>`
#9 319.5 52 | |     let db = client.database("db").collection::<Login>("coll");
#9 319.5 53 | |     let deb: Login = db.find_one(doc!{"user":"test"},None).await?;
#9 319.5 65 | |         .body(tera.render("index", &context).unwrap()).unwrap()
#9 319.5 66 | | }
#9 319.5    | |_- this function should return `Result` or `Option` to accept `?`
#9 319.5    = help: the trait `FromResidual<Result<Infallible, mongodb::error::Error>>` is not implemented for `Response<std::string::String>`

I tried to use result in many ways and it didn’t work either, is there a solution for this problem?

Hi! You have a couple of options here - you can either change the return type of the function to be a Result type, e.g.

async fn index(Form(login): Form<Login>) -> Result<Response<String>, Error> {

or you can unwrap the value:

	let client = Client::with_uri_str("mongodb+srv://user:pass@cluster0.um0c2p7.mongodb.net/?retryWrites=true&w=majority").await.unwrap();

Note that using unwrap means your code will panic if there’s an error, which will likely cause the program to terminate. This is fine for test code and proof of concept, but for anything beyond that I recommend using a Result. The Rust book has a good chapter on how to handle errors, if you haven’t read it yet I highly recommend it :slight_smile:

Hi!,
I have read the book but only understand when building projects.

I’m trying to create a login page using the following code:

async fn signin_form(Form(login): Form<Login>)-> Result<impl IntoResponse, Box<dyn Error>> {
	let db = Client::with_uri_str("mongodb+srv://user:pass@cluster0.um0c2p7.mongodb.net/?retryWrites=true&w=majority").await.unwrap().database("braq").collection::<Login>("users");
	let find = db.find_one(doc!{"user":&login.user},None).await?;
	//..
}

But this error appears:

#9 187.7 error[E0277]: the trait bound `fn(Form<Login>) -> impl Future<Output = Result<impl IntoResponse, Box<(dyn StdError + 'static)>>> {signin_form}: Handler<_, _, _>` is not satisfied
#9 187.7    --> src/main.rs:13:39
#9 187.7     |
#9 187.7 13  |         .route("/signin/", get(signin).post(signin_form))
#9 187.7     |                                        ---- ^^^^^^^^^^^ the trait `Handler<_, _, _>` is not implemented for fn item `fn(Form<Login>) -> impl Future<Output = Result<impl IntoResponse, Box<(dyn StdError + 'static)>>> {signin_form}`
#9 187.7     |                                        |
#9 187.7     |                                        required by a bound introduced by this call
#9 187.7     |
#9 187.7     = help: the following other types implement trait `Handler<T, S, B>`:
#9 187.7               <Layered<L, H, T, S, B, B2> as Handler<T, S, B2>>
#9 187.7               <MethodRouter<S, B> as Handler<(), S, B>>
#9 187.7 note: required by a bound in `MethodRouter::<S, B>::post`
#9 187.7    --> /usr/local/cargo/registry/src/github.com-1ecc6299db9ec823/axum-0.6.7/src/routing/method_routing.rs:618:5
#9 187.7     |
#9 187.7 618 |     chained_handler_fn!(post, POST);
#9 187.7     |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `MethodRouter::<S, B>::post`
#9 187.7     = note: this error originates in the macro `chained_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
#9 187.7 
#9 187.8 For more information about this error, try `rustc --explain E0277`.
#9 187.8 warning: `hello` (bin "hello") generated 1 warning
#9 187.8 error: could not compile `hello` due to previous error; 1 warning emitted
#9 ERROR: executor failed running [/bin/sh -c cargo build]: exit code: 101

I’m not at all familiar with Axum, but as far as I can tell from its documentation the return type needs to use StatusCode as the error type, not Box<dyn Error>; you’ll need to convert errors produced by methods you call within your handler to that.

I’d also recommend against creating a new Client for each request; Client construction is heavyweight, and while that will work, it’ll be slow. It looks like Axum provides good support for state shared across handlers, so that sounds like the way to go.

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.