Search code examples
dvibed

Use a variable with Vibe.d when rendering a template file with response.render


Currently I'm using Vibe.d to make a website, which has a Response class that's handed to every request. That looks something like this:

import vibe.d;

void index(HTTPServerRequest req, HTTPServerResponse res)
{
  res.render!("index.dt", req);
}

shared static this()
{
  auto router = new URLRouter;
  router.get("/", &index);

  auto settings = new HTTPServerSettings;
  settings.port = 8080;

  listenHTTP(settings, router);
}

In the example, I'm passing a const string "index.dt to the res.render! method, but I want to pass a variable:

void render(string action, HTTPServerResponse res) {
  res.render!(action);
}

But I get the following error:

Error: variable action cannot be read at compile time

In every spot I'm calling render, I've hardcoded strings:

render("foo.dt");

But that doesn't satisfy the compiler. Any idea how I can make this work?


Solution

  • While using a run time variable is not possible as a matter of principle (that would basically require compiling D code at run time), you could use a compile time defined enum constant or template parameters to avoid using the string constants directly:

    void index(string templ)(HTTPServerRequest req, HTTPServerResponse res)
    {
        res.render!(templ, req);
    }
    
    shared static this()
    {
        // ...
        router.get("/", &index!"index.dt");
        // BTW, this special case is equal to
        //router.get("/", staticTemplate!"index.dt");
        // ...
    }
    

    or using an enum:

    enum indexTemplateFile = "index.dt";
    
    void index(HTTPServerRequest req, HTTPServerResponse res)
    {
        res.render!(indexTemplateFile, req);
    }
    

    This alternative form of using a named enum can also be used:

    enum TemplateFile {
        index = "index.dt",
        login = "login.dt"
    }
    
    void index(HTTPServerRequest req, HTTPServerResponse res)
    {
        res.render!(TemplateFile.index, req);
    }
    

    Both of these approaches can also be combined and the constants can even be modified with the usual string operations, as long as the result can still be computed at compile time (e.g. it is possible to call something like std.string.toLower on the string before passing it to render).