Search code examples
rustrust-rocket

How to trigger Outcome::Failure in Rocket FromRequest implementation?


While trying to get started with development of an api using rocket, I was implementing a request guard which is supposed to check authorization headers. When the check fails it should result in a Failure, but that is where I cannot get it to work. Outcome::Success works perfectly fine and returns the correct object, but when triggering an Outcome::Failure I always run into the issue that I cannot get it to compile:

[package]
name = "api-sandbox"
version = "0.1.0"
edition = "2021"

[dependencies]
rocket = "0.5.0-rc.1"
regex = "1"
#[macro_use] extern crate rocket;

use rocket::Request;
use rocket::request::{FromRequest, Outcome};
use rocket::http::Status;
use regex::Regex;

#[get("/")]
fn index() -> &'static str {
    "Hello, world!"
}

#[get("/test")]
fn test(device: Device) -> &'static str {
    "Hello test"
}

#[derive(Debug)]
enum RequestError {
    InvalidCredentials,
    ParseError,
}

struct Device {
    id: i32
}

#[rocket::async_trait]
impl<'r> FromRequest<'r> for Device {
    type Error = RequestError;
    async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {

         Outcome::Failure((Status::BadRequest, RequestError::ParseError));

        // TEST
        let d1 = Device {
            id: 123
        };
        Outcome::Success(d1)
    }
}

#[launch]
fn rocket() -> _ {
    rocket::build().mount("/", routes![index,test])
}
error[E0282]: type annotations needed
  --> src/main.rs:43:21
   |
43 |                     Outcome::Failure((Status::BadRequest, RequestError::ParseError));
   |                     ^^^^^^^^^^^^^^^^ cannot infer type for type parameter S declared on the enum Outcome

I expected that the parameter S should not needed to be declared, as I am not using the parameter Success(S), but use Failure(E). According to the docs I can either return an error or an tuple with Status and Error, but instead the error message pops up. I have double checked with only available resources and blogs, but was not able to correctly trigger an outcome with status failure.


Solution

  • The type of Outcome::Failure(_) cannot be deduced. Even if not used in this particular construction, the type parameter S must be known for it to be a complete type. There is no default type available or any context that can help infer the type of S.

    The same is true of Outcome::Success(_). By itself, the type of the template parameter E is not known. However, this compiles because it does have context that can help the compiler infer it. It is used as a return value, so it must match the return type, and therefore it can be deduced that E is Self::Error.

    This will also work for Outcome::Failure(_) if it were used as a return value:

    async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
        Outcome::Failure((Status::BadRequest, RequestError::ParseError))
    }