SolvedRocket Easy question, how to return different type of response

EXAMPLE:

#[get("/<id>")]
fn user(id: isize) -> ??? { 
    if id < 0 {
        // invalid
        return Redirect::to(...);
    } else {
        return Template
    }
}

I tried Outcome in ??? but get some errors.

16 Answers

✔️Accepted Answer

For the benefit of anyone else coming here from google:

It seems like the most ergonomic way to do this in v0.4 is to make an enum for your response or error type, and derive Responder, as documented here:
https://rocket.rs/v0.4/guide/responses/#custom-responders
https://api.rocket.rs/v0.4/rocket_codegen/derive.Responder.html

So you can do something similar to AnyResponse like this:

use rocket::http::Cookies;
use rocket::response::Redirect;
use rocket_contrib::templates::Template;
use std::collections::HashMap;

#[derive(Debug, Responder)]
pub enum ExampleResponse {
    Template(Template),
    Redirect(Redirect),
}

#[get("/example")]
pub fn example(mut cookies: Cookies) -> ExampleResponse {
    if let Some(user_id) = cookies.get_private("user_id") {
        let ctx: HashMap<...> = HashMap::new();
        // add something to ctx with user id
        return ExampleResponse::Template(Template::render("app", ctx));
    }

    return ExampleResponse::Redirect(Redirect::to("/login"));
}

Other Answers:

but i think sometimes need two different successful Response, like this:

if xxx {
    return Redirect; // success and do redirect.
} else if xxx {
    return Template; // success and render a template to display.
} else {
    return Err; // fail
}

Hello, i also had this problem and i'm kinda disappointed that people put so little effort in posting decent examples here and in the rocket docs. Anyway, here's my solution, but i only started learning rust yesterday, so sorry if it's bad code.

responses.rs

use rocket_contrib::Template;
use rocket::response::{Redirect, Responder, Response};
use rocket::request::{Request};
use rocket::http::{Status};

pub struct AnyResponse {
    resType: &'static str,
    template: Option<Template>,
    redirect: Option<Redirect>
}

impl AnyResponse{
    fn getDefault() -> Self {
        AnyResponse{ resType: "", template: None, redirect: None }
    }
    pub fn template (temp: Template) -> Self {
        let mut res = AnyResponse::getDefault();
        res.resType = "template";
        res.template = Some(temp);
        return res
    }
    pub fn redirect (redi: Redirect) -> Self {
        let mut res = AnyResponse::getDefault();
        res.resType = "redirect";
        res.redirect = Some(redi);
        return res
    }
}

impl Responder<'static> for AnyResponse {
    fn respond_to(self, req: &Request) -> Result<Response<'static>, Status> {
        if self.resType == "template" {
            return Some(self.template).respond_to(req)
        }
        return Some(self.redirect).respond_to(req)
    }
}

main.rs

use std::collections::HashMap;
mod responses;

fn empty_hashmap() -> HashMap<String, String> {
    HashMap::<String, String>::new()
}

#[get("/")]
fn index(mut cookies: Cookies) -> responses::AnyResponse {
    let uid = cookies.get_private("user_id");
    if uid == None {
        return responses::AnyResponse::redirect(Redirect::to("/login"))
    }
    return responses::AnyResponse::template(Template::render("app", empty_hashmap()))
}

More Issues: