Capy-Bearer Documentation

9. Handling a web request

A Capy Bearer handler receives one copied request snapshot. Declare every handler with request : dval.

Read the request snapshot

function RENDER(request : dval) {
    var name := string(request.query.name, {fallback: "guest"})
    request.out.headers["Content-Type"] = "text/plain; charset=utf-8"
    print("Hello, ", name, "!\n")
}

Output

Hello, guest!

The snapshot contains method, query, form, params, headers, cookies, body, files, route, url, server, session, props, config, call, connection, unit, websocket, and out.

route contains path, page, raw_path, and valid. url contains script and base. session contains id, name, and values. websocket contains connection_id, scope, opcode, binary, and current-scope connections.

Missing members are none. Use normal conversions for scalar values. For example, use string(request.form.email), s32(request.websocket.opcode), and bool(request.websocket.binary).

Form a response

Use print, request.out.status, request.out.headers, request.out.cookies, and redirect to change the response. Use a redirect after a successful state change so the user can refresh the page safely.

Use ws_send, ws_send_to, and ws_close for WebSocket effects. Use request.websocket.connections to select current-scope clients.

Handle a form

A handler normally uses one route for both the form and the POST result. Read request.method first. Read submitted fields from request.form.

This example shows the complete control flow. A GET request prints the form. A POST request validates the email, stores it in the session, queues a cookie, and redirects. Use print for every HTML string that the handler must send. The documentation renderer runs the GET path.

function RENDER(request : dval) {
    request.out.headers["Content-Type"] = "text/html; charset=utf-8"
    var method := string(request.method, {fallback: "GET"})

    if method == "POST" {
        var email := string(request.form.email)
        if email == "" {
            request.out.status = 422
            print(<><p>Email is required.</p></>)
            return
        }

        var session := session_start("account")
        session = session_set("email", email)
        request.out.cookies["has_account"] = "1"
        redirect("/account")
        return
    }

    print(<>
        <form method="post">
            <label>Email <input name="email" type="email" /></label>
            <button>Save</button>
        </form>
    </>)
}

Read uploaded files

Uploaded files appear in request.files. Each entry is a copied dval with the metadata that Bearer accepted for the request. Treat the original filename as user input.

Use the generated request page for the exact file fields. Validate the file count, size, and type before you store anything.

function RENDER(request : dval) {
    var files := request.files
    print("files=", length(files), "\n")
}

Sessions

Session effects return a state map with id, name, and values. Keep the returned value when later code needs changed session data. The handler request snapshot does not change.

function RENDER(request : dval) {
    var session := session_start("account")
    session = session_set("theme", "dark")
    print(string(session.values.theme), "\n")
}

CLI and WebSocket handlers

Use CLI for a local command through Bearer's private CLI socket. Read command input from the copied request snapshot:

function CLI(request : dval) {
    print(string(request.body))
}

Use WS for each WebSocket message. Read the message from request.body. Read the connection ID, scope, opcode, binary flag, and current-scope connections from request.websocket:

function WS(request : dval) {
    ws_send(string(request.body), false)
}

RENDER, named RENDER, COMPONENT, named COMPONENT, CLI, WS, TASK, named TASK, INIT, ONCE, and custom HTTP handlers use request : dval. Handlers do not return application values.