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.
Please see the response section of the guide. This has answers to your question and much more.
@SergioBenitez I see the tutorial, I means how to return a Template in some case, and return Redirect in other.
should i write a response wrapper contains Redirect and Template, and impl the Responder trait?
I got the answer. just return Result<Response<'static>, Status>
You should be returning Result<Template, Redirect> in your example. You should very, very rarely return a Response directly.
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
}
@sbwtw That would require something like an Either type. Then you could return a Result<Either<Redirect, Template>, Error>. Unfortunately Rust doesn't have an Either type in the standard library, but it's trivial to implement one.
yes, so thats a reason i use Response directly. i think if we have a example in tutorial to show this is very helpful.
I use https://crates.io/crates/either @sbwtw; it works nicely. For something more complicated you should probably use your own enum type.
thanks @mehcode I will try this.
Anyone got an example of using Either in handler return types?
@Korvox I've added such a sample as a PR to the docs at https://github.com/SergioBenitez/Rocket/pull/493, let me know if you have any comments or an idea for a more representative example!
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()))
}
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"));
}
Most helpful comment
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: