Building a Server-Side Rendered Web App with Rust
Getting Started with Template Engines
Rust’s ecosystem offers a robust selection of template engines, providing developers with a range of options for their projects. In this tutorial, we’ll explore the traditional approach to building web applications using templates with server-side rendering. We’ll focus on Askama, a mature engine based on the popular Jinja project.
Setup and Dependencies
To follow along, you’ll need a recent Rust installation (1.39+) and a web browser. Create a new Rust project, and edit the Cargo.toml file to add the necessary dependencies: warp, tokio, Serde, Askama, uuid, chrono, and thiserror.
Data Storage
For our CRUD-like functionality, we’ll use a shared Vec of books protected by a read/write lock and stored in an Arc smart-pointer. This allows us to pass the data between threads.
Defining the Book Structure
We’ll define a Book structure and a useful WebResult type for our warp handlers. With the basic setup complete, let’s create a welcome handler to greet visitors.
Creating the First Template
In the handler module, create a data structure for the welcome page. We’ll include two hard-coded strings for the title and body of the page. The welcome.html file resides in the./templates/ folder and includes header.html and footer.html files.
Welcome Handler
The welcome_handler function creates an instance of the WelcomeTemplate struct, calls render(), and handles errors. We then return the result, rendered with warp’s reply::html function, to the client.
Implementing CRUD Functionality
We’ll define all the handlers for our warp server, including newbookhandler, createbookhandler, editbookhandler, and deletebookhandler. Each handler passes the data memory-based data storage and defines path::param for the edit and delete endpoints.
Listing Books
The listbookshandler uses the book/list.html template, acquires a read-lock on our shared data storage, and passes a reference to the books vector to the template. If an error occurs, we convert it to a custom error and return it.
Editing and Deleting Books
The editbookhandler finds the book with the given ID in our “database” or returns an error. The doeditbookhandler mutates the book in place using the data from the body. The deletebook_handler removes the book from the list or returns an error if it isn’t found.
Basic Error Handling
We’ll create a template for showing errors to our users. The handle_rejection function in the error module checks for different error cases, sets useful error messages and response codes, and renders the ErrorTemplate.
Wiring Everything Together
We’ll create a warp web server, and if you start this application with cargo run and navigate to http://localhost:8080, you’ll see a fully server-rendered UI you can interact with.
The Power of Template Engines
Rust’s ecosystem provides many different options for template engines, each with its own trade-offs. By choosing the right engine for your project, you can ensure safe, performant template rendering.
Debugging and Performance Monitoring
LogRocket provides full visibility into web frontends for Rust apps, allowing you to monitor and track performance, automatically surface errors, and track slow network requests and load time. Try LogRocket for free today!