Template Syntax Reference

Complete guide to ScribeEngine .stpl file syntax.

Route Declaration

Basic Routes

@route('/')              # GET request (default)
@route('/about')         # Static path
@route('/api/data')      # Nested path

HTTP Methods

@route('/login', methods=['GET', 'POST'])
@route('/api/users', methods=['GET', 'POST', 'PUT', 'DELETE'])

Route Parameters

@route('/posts/<int:post_id>')                # Integer
@route('/users/<username>')                   # String (default)
@route('/files/<path:filepath>')              # Path (includes slashes)
@route('/product/<uuid:product_id>')          # UUID

Python Blocks

Execute Python code with {$ ... $}:

{$
# Variables
title = "Hello"
items = [1, 2, 3]

# Loops
for item in items:
    process(item)

# Conditionals
if user_id:
    user = db['default'].find('users', user_id)

# Functions
def format_date(date):
    return date.strftime('%Y-%m-%d')
$}

Available Objects

  • request - Flask request object (form data, headers, method)
  • session - Flask session (dict-like)
  • db - Database connections
  • flash() - Flash messages
  • redirect() - Redirect to URL
  • abort() - Return HTTP error
  • jsonify() - Return JSON response

Jinja2 Templates

Variables

<h1>{{ page_title }}</h1>
<p>{{ user.name }}</p>
<p>{{ items[0] }}</p>

Filters

{{ name | upper }}                    # UPPERCASE
{{ long_text | truncate(100) }}       # Limit length
{{ date | default('No date') }}       # Default value

Conditionals

{% if user %}
    <p>Welcome, {{ user.name }}!</p>
{% else %}
    <p>Please log in.</p>
{% endif %}

Loops

{% for post in posts %}
    <h2>{{ post.title }}</h2>
{% endfor %}

{% for key, value in dict.items() %}
    <p>{{ key }}: {{ value }}</p>
{% endfor %}

Decorators

@require_auth

Require login:

@route('/dashboard')
@require_auth
{$ ... $}

Redirects to /login if not authenticated.

@no_layout

Disable the automatic base.stpl wrapper. Useful for HTMX fragments or AJAX responses.

@route('/api/fragment')
@no_layout
{$ ... $}
<div>I am a bare HTML snippet</div>

@sse

Enable Server-Sent Events (SSE). This decorator:

  1. Sets the response mimetype to text/event-stream.
  2. Automatically applies @no_layout.
  3. Supports yield for streaming updates.
@route('/counter')
@sse
{$
import time
for i in range(5):
    count = i
    yield frame() # Renders the template below
    time.sleep(1)
$}
<div class="update">Current count: {{ count }}</div>

Built-in Helpers

frame(template=None, event=None, **kwargs)

Used within @sse routes to render fragments for the stream.

  • template: Optional override for the template to render. Defaults to the route's own template.
  • event: Optional SSE event name (e.g., event: update).
  • kwargs: Extra variables to pass to the template.
yield frame(event='notification', msg='New Alert!')

Return Statements

Redirect

{$
if not user:
    return redirect('/login')
$}

JSON Response

{$
data = {"status": "success", "count": 42}
return jsonify(data)
$}

Abort (HTTP Error)

{$
if not authorized:
    return abort(403)  # Forbidden
$}

Layout Inheritance

Use base.stpl automatically:

@route('/page')
{$
page_title = "My Page"  # Sets <title>
$}

<!-- Content automatically wrapped in base.stpl -->
<h1>Hello!</h1>