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>