A Web App in Rust - 03 Complex Templates
Tags: webdev, rust, tutorial, actixweb
Published: 2020-10-25 14:41:07


Welcome back! We now have an application that can use HTML templates to render some basic data and serve it as an actual web page. In this chapter, we will work on making our template a little bit more complex and work on translating Rust objects into something tera can use.

The translation of Rust objects requires us to serialize our structs. We can do this with the help of the serde crate.

Add serde to our dependencies.

./Cargo.toml
```
[dependencies]
actix-web = "3"
tera = "1.5.0"
serde = "1.0"
```

We can then update our main.rs file.

./src/main.rs
``` rust
...
use serde::Serialize;

#[derive(Serialize)]
struct Post {
    title: String,
    link: String,
    author: String,
}

async fn index(tera: web::Data<Tera>) -> impl Responder {
    let mut data = Context::new();

    let posts = [
        Post {
            title: String::from("This is the first link"),
            link: String::from("https://example.com"),
            author: String::from("Bob")
        },
        Post {
            title: String::from("The Second Link"),
            link: String::from("https://example.com"),
            author: String::from("Alice")
        },
    ];

    data.insert("title", "Hacker Clone");
    data.insert("posts", &posts);

    let rendered = tera.render("index.html", &data).unwrap();
    HttpResponse::Ok().body(rendered)
}
...
```

The first thing we do is include serde into our file and pull Serialize.

Because we are creating a Hacker News clone, I made a struct that we may possibly use in the future. For now it will only contain a title, a link and an author. A user will come to our site and on the index page they will see a list of articles that they can read and comment on. 

This struct is the object that we want to serialize so that we can have Tera render the object without us moving all the data in the struct to the tera Context manually. We add the derive statement to our struct and it will then be given automatic serialization.

Inside our index function, we create an array of posts that we can then loop through in our template file.

The next step is to insert the array of posts into our tera Context in this case it is called data.

We then pass data and the page we want to use to tera.render and we will then get an HTML string that we can then return to the user.

At this point we have everything working except we don't do anything with this new data in our template. Let's fix that!

Update our index.html file in our templates folder.

./templates/index.html
``` html
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>{{title}}</title>
    </head>
    <body>
        {% for post in posts %}
        <div>
            <a href="{{ post.link }}">{{ post.title }}</a>
            <small>{{ post.author }}</small>
        </div>
        {% endfor %}
    </body>
</html>
```

Here we use the looping construct to loop through our posts and we can see that the object has been translated exactly, the struct in rust is available to us in the template and this is because we used serde and serialization.

Now if you navigate to 127.0.0.1:8000 you should see a list of links on our home page! Slowly but surely, we're getting somewhere!