Over the holidays I have enjoyed playing a little with Rocket. Here are a couple of things I’ve written which might be useful to others when prototyping a new site using rocket.

Firstly, the examples show you how to create an instance of a struct from either a Query or a Form, but when using a template (I am using a rust implementation of Handlebars) it can be useful to just pass all of the fields through as a map. Here are two simple methods (one for Form, another for Query) which populate a HashMap with the incoming data.

struct RequestMap {
    map: HashMap<String,String>
}

impl<'f> FromForm<'f> for RequestMap {
    type Error = ();

    fn from_form(items: &mut FormItems<'f>, _strict: bool) -> Result<RequestMap, ()> {
        let mut map = HashMap::new();

        for item in items {
            let k = item.key.url_decode().map_err(|_| ())?;
            let v = item.value.url_decode().map_err(|_| ())?;
            map.insert(k, v );

        }

        Ok(RequestMap { map})
    }
}

impl FromQuery<'_> for RequestMap {
    type Error = ();

    fn from_query(items: Query) -> Result<RequestMap, ()> {
        let mut map = HashMap::new();
        for item in items {
            let k = item.key.url_decode().map_err(|_| ())?;
            let v = item.value.url_decode().map_err(|_| ())?;
            map.insert(k, v );

        }

        Ok(RequestMap { map})
    }
}

We create a struct RequestMap which contains just a HashMap, then implement the methods FromForm and FromQuery on the map.

Now these maps can be used in routes as follows:

#[get("/example_get/<name>?<params..>")]
fn example_get_route(name: String, params: RequestMap) -> Template {
    Template::render(name, &params.map)
}

#[post("/example_post/<name>", data="<params>")]
fn example_post_route(name: String, params: Form<RequestMap>) -> Template {
    Template::render(name, &params.into_inner().map)
}

In these examples I have also set up a name parameter which maps to the template name, so you can copy and paste templates around and try them out with different parameters easily.

The second Thing I have found useful in prototyping with Rocket is to set up a Handlebars helper to print out information from the provided context. You can put this in to render as a comment in your template so that you can easily see what context is being provided to your template.

Here is the helper definition:

#[derive(Clone,Copy)]
struct DebugInfo;

impl HelperDef for DebugInfo {
    fn call<'reg:'rc,'rc> (&self, h: &Helper, _: &Handlebars, ctxt: &Context, rc: &mut RenderContext, out: &mut dyn Output) -> HelperResult {
        out.write(&format!("Context:{:?}",ctxt.data()))?;
        out.write(&format!("Current Template:{:?}", rc.get_current_template_name()))?;
        out.write(&format!("Root Template:{:?}", rc.get_root_template_name()))?;
        for (key, value) in h.hash() {
            out.write(&format!("HashKey:{:?}, HashValue:{:?}",key, value))?;
        }
        Ok(())
    }
}

and you set it up like this in the Rocket initialisation:

rocket::ignite().mount("/", routes![index,example_get_route,example_post_route])
        .attach(Template::custom(|engines|{
            engines.handlebars.register_helper("debug", Box::new(DebugInfo));
        }))

To use this as a helper, put something like this inside your Handlebars template:

<!--{{debug nameparam=username}}-->

The output should look something like this:

<!--Context:Object({"username": String("aa")})Current Template:Some("testroute")Root Template:Some("testroute")HashKey:"nameparam", HashValue:PathAndJson { relative_path: Some("username"), value: Context(String("paul"), ["username"]) }-->

The above is for a get request where the URL was http:///testroute?username=paul

Thanks for reading. I hope the above proves useful - I am still experimenting with Rocket (also with writing Handlebars helpers and combining all this with htmx ), so there may be simpler or better ways of achieving the above. If you know of one, or if you have any questions, suggestions, or to point out any mistakes, please contact me at the email address below. I’d love to hear from you.