Template Engine
Built-in template engine for rendering dynamic HTML pages.
Overview
Features: - Variable substitution - Conditionals - Loops - Filters - Template caching - HTML auto-escaping
Basic Usage
#include "crest/crest.hpp"
#include "crest/template.hpp"
int main() {
crest::App app;
crest::TemplateEngine::Config config;
config.template_dir = "./templates";
config.extension = ".html";
config.cache_enabled = true;
config.auto_escape = true;
crest::TemplateEngine engine(config);
app.get("/", [&engine](crest::Request& req, crest::Response& res) {
crest::TemplateContext context = {
{"title", "Home Page"},
{"username", "Alice"},
{"logged_in", true}
};
std::string html = engine.render("index", context);
res.html(200, html);
});
app.run("0.0.0.0", 8000);
return 0;
}
Template Syntax
Variables
Conditionals
{% if logged_in %}
<p>You are logged in</p>
{% endif %}
{% if is_admin %}
<a href="/admin">Admin Panel</a>
{% endif %}
Filters
Built-in Filters
upper
- Convert to uppercaselower
- Convert to lowercasecapitalize
- Capitalize first letter
Custom Filters
engine.add_filter("reverse", [](const std::string& s) {
return std::string(s.rbegin(), s.rend());
});
engine.add_filter("truncate", [](const std::string& s) {
return s.length() > 50 ? s.substr(0, 50) + "..." : s;
});
Usage in template:
Global Variables
engine.add_global("site_name", "My Website");
engine.add_global("version", "1.0.0");
engine.add_global("year", 2024);
Access in any template:
Template Inheritance
Base Template (base.html)
<!DOCTYPE html>
<html>
<head>
<title>{{ title }} - {{ site_name }}</title>
</head>
<body>
<header>
<h1>{{ site_name }}</h1>
</header>
<main>
<!-- Content goes here -->
</main>
<footer>
<p>© {{ year }} {{ site_name }}</p>
</footer>
</body>
</html>
Child Template (page.html)
Render String
std::string template_str = "<h1>{{ title }}</h1><p>{{ message }}</p>";
crest::TemplateContext context = {
{"title", "Hello"},
{"message", "Welcome to Crest!"}
};
std::string html = engine.render_string(template_str, context);
Complete Example
Template (profile.html)
<!DOCTYPE html>
<html>
<head>
<title>{{ username }}'s Profile</title>
</head>
<body>
<h1>{{ username|capitalize }}</h1>
{% if is_verified %}
<span class="badge">Verified</span>
{% endif %}
<div class="info">
<p>Email: {{ email|lower }}</p>
<p>Member since: {{ join_date }}</p>
</div>
{% if is_admin %}
<div class="admin-panel">
<h2>Admin Controls</h2>
<button>Manage Users</button>
</div>
{% endif %}
</body>
</html>
Application Code
#include "crest/crest.hpp"
#include "crest/template.hpp"
int main() {
crest::App app;
crest::TemplateEngine engine;
engine.add_global("site_name", "My App");
engine.add_global("year", 2024);
app.get("/profile/:username", [&engine](crest::Request& req, crest::Response& res) {
// Get user data (simplified)
crest::TemplateContext context = {
{"username", "alice"},
{"email", "alice@example.com"},
{"join_date", "2024-01-15"},
{"is_verified", true},
{"is_admin", false}
};
std::string html = engine.render("profile", context);
res.html(200, html);
});
app.run("0.0.0.0", 8000);
return 0;
}
Blog Example
#include "crest/crest.hpp"
#include "crest/template.hpp"
struct Post {
std::string title;
std::string content;
std::string author;
std::string date;
};
int main() {
crest::App app;
crest::TemplateEngine engine;
std::vector<Post> posts = {
{"First Post", "Content here", "Alice", "2024-01-01"},
{"Second Post", "More content", "Bob", "2024-01-02"}
};
app.get("/blog", [&engine, &posts](crest::Request& req, crest::Response& res) {
// Render blog list
std::string html = "<h1>Blog Posts</h1>";
for (const auto& post : posts) {
crest::TemplateContext context = {
{"title", post.title},
{"author", post.author},
{"date", post.date}
};
html += engine.render_string(
"<article>"
"<h2>{{ title }}</h2>"
"<p>By {{ author }} on {{ date }}</p>"
"</article>",
context
);
}
res.html(200, html);
});
app.run("0.0.0.0", 8000);
return 0;
}
Cache Management
// Clear template cache
engine.clear_cache();
// Disable caching for development
crest::TemplateEngine::Config config;
config.cache_enabled = false;
crest::TemplateEngine engine(config);
HTML Escaping
Auto-escaping is enabled by default to prevent XSS attacks:
crest::TemplateContext context = {
{"user_input", "<script>alert('XSS')</script>"}
};
// Renders as: <script>alert('XSS')</script>
Disable for trusted content:
Best Practices
- Enable caching in production
- Use auto-escaping for user input
- Keep templates in separate directory
- Use template inheritance for consistency
- Add global variables for common data
- Create custom filters for reusable logic
- Clear cache when templates change
- Validate template context data
- Handle missing templates gracefully
- Use meaningful variable names