Using MiniJinja Templates for Dynamic Web Pages with Rust's Axum Server
I use Axumaxum to power a local admin server for this site. It's provides reports on the site's current build state and various CRUD operations to manage content. These tools are Server Side Renderedssr using the MiniJinjamj template engine.
MiniJinja sets up an initial environment before rendering templates. I use axum's `State` to load and store the environment for the admin server when it initializes. Without that, it would have to initialize on every page request.
Here's what the setup looks like:
Files
Cargo.toml
src/main.rs
templates/index.html
Notes
-
I'm using the anyhow crate to make error handling easier between MiniJinja and file system calls. It's not necessary for the Axum/MiniJinja functionality.
-
I split creation of the MiniJinja environment to its own function. The
env.set_loader()line uses a target directory for template storage.The
env.set_syntax()call configures MiniJinja for my preferred setup (e.g. using[@ @]and the like instead of{{ }}for tokens since I find they make the page easier to read. -
I also split rending to its own
renderfunction. Any number of handlers (e.g.handle_home) can use it by setting up a context and passing it along with a template name and the state to get the rendered content back.The
render()function throws an 500 Internal Server Error if there's a problem. -
The
date()function is defined in the Rust file and run every time the template renders so the value is updated for every page load.
Wrap-Up
I'm really happy with this approach. MiniJinja offers a ton of functionality out of the box. One of those features is creating custom functions. The ability to call those functions each time the page is requested is to populate the template covers every scenario I can think of.
-a
Footnotes
-
axum Rust's axum crate provides the HTTP routing and request handling needed to build a web server that hosts dynamic pages. It reminds me a lot of Python's Flask project.
-
ssr Server Side Rendering is when a server builds the response for each request dynamically when the request arrives. An alternate approach is Static Site Generation which pre-builds all the pages prior to any requests. When one comes in, the server responds with the pre-built payload. It's faster and uses fewer resources and the cost of not being able to customize the responses for each request. (There are, of course, hybrid approaches as well.)
-
mj MiniJinja is the Rust version of Python's Jinja2 template engine. It provides looping, conditionals, and functions to render pages. It's fantastic.