res.render()¶
Render another command's source code as the HTTP response. Ideal for separating API logic from HTML/JSON templates — keep your handler lean, your templates dumb.
Execution ends as soon as the rendered content is sent.
Basic usage¶
// Render by exact command name
res.render("profile.html")
// Pass template data
res.render("api-response.json", {
data: { ok: true, result: computed }
})
// Override content type
res.render("export", {
contentType: "text/csv",
data: { rows: csvRows }
})
If the command name is not found, res returns 404 JSON:
Automatic content type¶
res.render() sets Content-Type from the command name extension, unless you pass options.contentType.
| Extension | Content-Type |
|---|---|
.html, .htm | text/html |
.css | text/css |
.js, .mjs | application/javascript |
.json, .jsonld | application/json |
.xml | application/xml |
.csv | text/csv |
.yaml, .yml | application/x-yaml |
.md, .markdown | text/markdown |
.svg | image/svg+xml |
.ts, .tsx, .jsx, .vue, … | Matching script types |
| (no extension) | text/plain |
res.render("page.html") // text/html
res.render("data.json") // application/json
res.render("styles.css") // text/css
res.render("readme") // text/plain
Data passing¶
Pass custom fields via options.data. They are merged into the EJS template context alongside globals.
// URL: /webapp/{bot_id}/showProfile?section=settings
res.render("profile-template.html", {
data: {
profile: userProfile,
section: params.section || "overview"
}
})
Inside profile-template.html:
Available in rendered templates¶
| Source | Variables |
|---|---|
| Platform | bot, user, chat, owner, params, request, update_type |
options.data | Any keys you pass (e.g. profile, stats) |
| Parent command | Full TBL sandbox — Api, Bot, db, HTTP, modules, etc. run before render; the template only sees template context |
Note
user is available in templates only when the parent command runs in a user webhook context.
EJS in rendered commands¶
For .html and .text commands, if the command code contains <%, it is EJS-rendered with options.data before sending.
HTML commands also receive platform HTML injection (<base>, meta tag, attribution).
Try it — copy-paste examples¶
Separate API logic from HTML¶
Handler command (showDashboard):
let stats = {
users: await db.bot.get("user_count") || 0,
revenue: await db.bot.get("revenue") || 0
}
res.render("dashboard.html", { data: { stats } })
Template command (dashboard.html):
<!DOCTYPE html>
<html>
<body>
<h1>Dashboard</h1>
<p>Users: <%= stats.users %></p>
<p>Revenue: <%= stats.revenue %></p>
</body>
</html>
JSON via template command¶
res.render("user-payload.json", {
data: {
id: user.id,
name: user.first_name,
premium: user.premium || false
}
})
user-payload.json command:
JSON API without a template file¶
For simple APIs, res.json() is often enough:
res.status(200)
.set("Access-Control-Allow-Origin", "*")
.json({ status: "success", data: userData })
See also¶
- HTML & EJS —
html(),renderEJS() - JSON, Text & XML
- Defaults & Protection