Examples#
Simple query list#
var users = `SELECT id, name FROM users`.fetch
var title = "๐๏ธ Users list"
return <!doctype html>
<html>
<head><title>{{ title }}</title></head>
<body style="font: 1.5em/2.5 system-ui; text-align:center">
<h1>{{ title }}</h1>
{{ users.count > 0 ?
<ul style="list-style-type:none">
{{ users.map{|user| <li>
<a href="/hello?id={{ user["id"] }}">
๐ {{ user["name"] }}
</a>
</li> } }}
</ul> :
/* Users table is empty */
<p>No users, go to <a href="/hello">hello</a>.</p>
}}
<p><a href=".">Back โฉ๏ธ</a></p>
</body>
</html>
Hello World#
// We create a class that that contains the logic and template.
// This is not required by Bialet, but it is a good practice.
// Once the logic and template become too big, you should split it
// in multiple classes.
class App {
// The name of the constructor could be anything.
construct new() {
_title = "๐ฒ Welcome to Bialet"
}
// Fetch the user's name from the database using plain SQL
// or return "World" if the user doesn't exist.
// Single line methods return the value of the expression.
name(id) { `SELECT name FROM users WHERE id = ?`.val(id) || "World" }
// Build the HTML
html(content) {
return <!doctype html>
<html>
<head>
<title>{{ _title }}</title>
</head>
<body style="font: 1.5em/2.5 system-ui; text-align:center">
<h1>{{ _title }}</h1>
{{ content }}
<p><a href="simple">Back to List ๐ฅ</a></p>
<p><a href=".">to Home โฉ๏ธ</a></p>
</body>
</html>
}
}
// We use the `get()` method to get the `id` parameter from the URL.
var id = Request.get("id")
// Create an instance of the `App` class.
var app = App.new()
// Generate the HTML, with the name of the user.
return app.html(<p>๐ Hello <b>{{ app.name(id) }}</b></p>)
Count the visitors of your website#
// We use the `query()` method to execute SQL statements.
// In this case we create a table named `counter` with two columns: `name` and `value`.
// Then we insert a row with the name `visits` and a value of 0, if there is no row
// with the name `visits`.
// This should be done with migrations; it's included here so the example is self-contained.
`CREATE TABLE IF NOT EXISTS counter (name TEXT PRIMARY KEY, value INTEGER)`.query
`INSERT OR IGNORE INTO counter (name, value) VALUES ("visits", 0)`.query
// This is the proper start of the script...
// We increment the value of the row with the name `visits` by 1.
`UPDATE counter SET value = value + 1 WHERE name = "visits"`.query
// We use the `val()` method to get the value of the first row in the query result.
var visits = `SELECT value FROM counter WHERE name = "visits"`.val
// We use the `return` to finish the script and send the response to the client.
// The `{{ ... }}` syntax is used to interpolate the value of the `visits` variable.
// Apart from the interpolation, the string is regular HTML.
return <!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Total times visited: <strong>{{ visits }}</strong></h1>
<p>
โน๏ธ Reload the browser or
<a href="">click here</a>
to see the new value.<p>
<p><a href=".">Back โฉ๏ธ</a></p>
</body>
</html>
Count the clicks#
// We use the `query` method to execute SQL statements.
// In this case we create a table named `counter` with two columns: `name` and `value`.
// Then we insert a row with the name `clicks` and a value of 0, if there is no row
// with the name `clicks`.
// This should be done with migrations; it's included here so the example is self-contained.
`CREATE TABLE IF NOT EXISTS counter (name TEXT PRIMARY KEY, value INTEGER)`.query
`INSERT OR IGNORE INTO counter (name, value) VALUES ("clicks", 0)`.query
// We use the `get()` method to get a parameter from the URL.
// When the parameter is `count`, we increment the value of the `clicks` row by 1.
if (Request.get("count")) {
`UPDATE counter SET value = value + 1 WHERE name = "clicks"`.query
}
// When the parameter is `reset`, we reset the value of the `clicks` row to 0.
if (Request.get("reset")) {
`UPDATE counter SET value = 0 WHERE name = "clicks"`.query
}
// We use the `val()` method to get the value of the first row in the query result.
var clicks = `SELECT value FROM counter WHERE name = "clicks"`.val
// We use the `return` to finish the script and send the response to the client.
// The `{{ ... }}` syntax is used to interpolate the value of the `clicks` variable.
// Apart from the interpolation, the string is regular HTML.
return <!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Total times clicked: <strong>{{ clicks }}</strong></h1>
<p>
<a href="clicks?count">Click me! ๐บ</a>
โข
<a href="clicks?reset">Reset ๐งน</a>
</p>
<p><a href=".">Back โฉ๏ธ</a></p>
</body>
</html>
Form submission#
// We use the `query` method to execute SQL statements.
// In this case we create a table named `counter` with two columns: `name` and `value`.
// Then we insert a row with the name `form` and a value of 0, if there is no row
// with the name `form`.
// This should be done with migrations; it's included here so the example is self-contained.
`CREATE TABLE IF NOT EXISTS counter (name TEXT PRIMARY KEY, value INTEGER)`.query
`INSERT OR IGNORE INTO counter (name, value) VALUES ("form", 0)`.query
// Set the initial value to 1
var value = 1
// We use the `isPost` property to check if the request method is POST.
if (Request.isPost) {
// We use the `post()` method to get a parameter from the form.
// `|| "1"` guards against `null`: `Request.post()` returns `null` when the key is missing.
value = Request.post("value") || "1"
// We use the `query` method to execute SQL statements.
// In this case we update the value of the `form` row by the value of the `value`
// parameter.
// Note the use of the `?` placeholder for the value of the `value` parameter.
// All the queries are run as a prepared statement. You can't concatenate query strings.
`UPDATE counter SET value = value + ? WHERE name = "form"`.query(value)
}
// We use the `val()` method to get the value of the first row in the query result.
var total = `SELECT value FROM counter WHERE name = "form"`.val
// We use the `return` to finish the script and send the response to the client.
// The `{{ ... }}` syntax is used to interpolate the value of the `total` variable.
// and the `value` variable.
// Apart from the interpolation, the string is regular HTML.
return <!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Total sum: <strong>{{ total }}</strong></h1>
<form method="POST">
<input type="text" name="value" value="{{ value }}">
<button type="submit">Submit</button>
</form>
<p><a href=".">Back โฉ๏ธ</a></p>
</body>
</html>
JSON Response#
// Response and Db are built-in classes โ no imports needed.
// Use the `query()` method to execute SQL statements.
// This creates a table named `counter` with two columns: `name` and `value`.
// In production this should be done with migrations; it's included here
// so the example is self-contained.
`CREATE TABLE IF NOT EXISTS counter (name TEXT PRIMARY KEY, value INTEGER)`.query()
// We use the `fetch()` method to get the query result as an array of objects.
var counters = `SELECT * FROM counter ORDER BY name ASC`.fetch()
// We use the `cors` method to enable Cross-Origin Resource Sharing (CORS).
// When the request method is OPTIONS, it will respond with the appropriate headers
// and a 204 No Content status, then return early.
if (Response.cors) return
// We use the `json()` method to send the query result as a JSON.
// This will add the header `Content-Type: application/json`.
Response.json(counters)
Form Upload#
if (Request.isPost) {
// Get the uploaded file
var uploadedFile = Request.file("form_file_name")
if (uploadedFile == null) {
return Response.end(400, "โ Upload Error", "No file was uploaded. Please select a file first.")
}
System.print("File: %(uploadedFile.name)")
// Make it temporal, it will be deleted soon
// You can still use it in the rest of the request
uploadedFile.temp
// Return the file to the browser
return Response.file(uploadedFile.id)
}
var title = "Upload File"
return <!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ title }}</title>
<style>body{ font: 1.3em system-ui; text-align: center }</style>
</head>
<body>
<h1>{{ title }}</h1>
<form method="post" enctype="multipart/form-data">
<input type="file" name="form_file_name">
<input type="submit" value="{{ title }}">
</form>
<p><a href=".">Back โฉ๏ธ</a></p>
</body>
</html>
File Creation#
import "random" for Random
// Generate an emoji SVG
var random = Random.new()
var emojis = ["๐", "๐", "โค๏ธ", "๐", "๐"]
var svg = <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<text y=".9em" font-size="90">{{ random.sample(emojis) }}</text>
</svg>
// Save the svg in a file
var file = File.create("emoji.svg", "image/svg+xml", svg)
// Send the file
Response.file(file.id)
HTTP API Call#
var res = Http.get("https://dummyjson.com/users?limit=5&select=username,email")
var users = res["users"]
System.log("Users: %(users)")
return <!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Show all the users from the DummyJSON API</h1>
{{ /* The interpolated string can have comments on it */
users.count > 0 ?
<table>
<tr>
<th>Name</th>
<th>Email</th>
</tr>
{{ /* List all the users */
users.map{|user| <tr>
<td>{{ user["username"] }}</td>
<td>{{ user["email"] }}</td>
</tr> } }}
</table> :
/* If there are no users */
<p>No user found</p>
}}
<p><a href=".">Back โฉ๏ธ</a></p>
</body>
</html>
Password utilities#
// We use the `post()` method to get a parameter from the POST request.
// `|| ""` guards against `null`: `Request.post()` returns `null` when the key is missing.
var password = Request.post('password') || ""
var passwordCheck = Request.post('password-check') || ""
// Set up the hash and verify variables
var encrypted
var verify
// We use the `isPost` property to check if the request method is POST
if (Request.isPost) {
// Hash the password. The hash is a string that includes the salt.
// The salt is randomly generated. The same password will have a different salt each time the `hash()` method is called.
// The hash use SHA-256 to encode the password with the salt.
encrypted = Util.hash(password)
// Verify the password against the hash
verify = Util.verify(passwordCheck, encrypted)
}
// We use the `return` to finish the script and send the response to the client.
// The `{{ ... }}` syntax is used to interpolate the value inputs.
// Apart from the interpolation, the string is regular HTML.
return <!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Password utilities</h1>
{{ Request.isPost && <div>
<p>Hash:</p>
<code>{{ encrypted }}</code>
<p><strong>{{ verify ? 'The passwords are the same' : 'The passwords are different' }}</strong></p>
<hr>
</div>
}}
<form method="POST">
<p>
<label for="password">Password</label>
</p>
<p>
<input type="password" name="password" value="{{password}}">
</p>
<p>
<label for="password-check">Password to check</label>
</p>
<p>
<input type="password" name="password-check" value="{{passwordCheck}}">
</p>
<p>
<button>Submit</button>
</p>
</form>
<p><a href=".">Back โฉ๏ธ</a></p>
</body>
</html>
Cross site request forgery#
var session = Session.new()
var verify
// We use the `isPost` property to check if the request method is POST
if (Request.isPost) {
// Verify that the CSRF token is valid
verify = session.csrfOk
}
return <!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Cross-Site Request Forgery</h1>
<p>Use different tabs to verify the post is from the last window.</p>
{{ Request.isPost &&
<p><strong>{{ verify ? 'The post is valid' : 'The post come from someone else' }}</strong></p>
}}
<form method="POST">
{{ session.csrf }}
<p>
<button>Submit</button>
</p>
</form>
<p><a href=".">Back โฉ๏ธ</a></p>
</body>
</html>
Markdown#
var markdown = """
# Markdown Example
This is written in Markdown.
[Back โฉ๏ธ](.)
This is the example.md file:
"""
return <!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
</head>
<body>
{{ Markdown.html(markdown) }}
<div style="text-align: left">
{{ Markdown.file("example.md") }}
</div>
</body>
</html>
Path-based route (users.wren)#
A single file serving both /users (list) and /users/:id (detail) via
Request.route(0). See Advanced Routing.
// --- Path-Based Route (folder.wren) ---
// Demonstrates: a single file serving both the bare URL and every deeper
// path. users.wren handles /users (list) and /users/:id (detail) by reading
// Request.route(0). See advanced-routing.md for details.
var id = Request.route(0)
if (id == null) {
var users = `SELECT id, name FROM users ORDER BY name`.fetch
return <!doctype html>
<html>
<head><title>Users</title></head>
<body style="font: 1.5em/2.5 system-ui; text-align:center">
<h1>Users</h1>
{{ users.count > 0 ?
<ul style="list-style-type:none">
{{ users.map{|user| <li>
<a href="/users/{{ user["id"] }}">๐ค {{ user["name"] }}</a>
</li> } }}
</ul> :
<p>No users yet.</p>
}}
</body>
</html>
}
var user = `SELECT id, name FROM users WHERE id = ?`.first(id)
if (!user) return Response.notFound()
return <!doctype html>
<html>
<head><title>{{ user["name"] }}</title></head>
<body style="font: 1.5em/2.5 system-ui; text-align:center">
<h1>๐ค {{ user["name"] }}</h1>
<p>User id: {{ user["id"] }}</p>
<p><a href="/users">โ Back to users</a></p>
</body>
</html>