Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

API reference

Every method an app may call, with its signature. Generated from stdlib/sig/*.rbs.

This page is written by stdlib/bin/melee-docs-api from the RBS signatures, so it lists exactly what the compiler is told the surface is. It is a list, not an explanation: for what each area is for, with worked examples, read the pages it links to — the app, the request, the response, templates, the database, durable objects, outbound HTTP, logging and security.

Types are RBS. ?x is an optional parameter, x: a required keyword, bot a method that never returns, and untyped a value Spinel is not told the type of. A heading is spelled the way an app calls it: Melee::HTTP.get on the module, Melee::DB#query on an instance, and a bare name for the top-level surface.

At a glance

  • The top-level surface
  • Routes and filtersget, post, put, patch, delete, before, not_found, error, title, app_title
  • The current requestrequest, params, form, query, session, log, db
  • Responsesredirect, back, halt, status, header, json, text, html
  • Templates (generated per app by the build step from views/)render, partial, h
  • Strings, security and settingsurl_encode, url_decode, csrf_token, csrf_field, secure_equal?, random_token, setting
  • MeleeMelee.db, Melee.env
  • Melee::ParamsMelee::Params#[], Melee::Params#fetch, Melee::Params#key?, Melee::Params#to_h, Melee::Params#each, Melee::Params#empty?
  • Melee::RequestMelee::Request#method, Melee::Request#path, Melee::Request#query, Melee::Request#host, Melee::Request#scheme, Melee::Request#remote_addr, Melee::Request#headers, Melee::Request#body, Melee::Request#log, Melee::Request#id, Melee::Request#params, Melee::Request#path_params, Melee::Request#header, Melee::Request#content_type, Melee::Request#base_url, Melee::Request#get?, Melee::Request#post?, Melee::Request#query_params, Melee::Request#form, Melee::Request#json, Melee::Request#cookies, Melee::Request#session, Melee::Request#env, Melee::Request.url_encode, Melee::Request.url_decode
  • Melee::ResponseMelee::Response#status, Melee::Response#headers, Melee::Response#body, Melee::Response.html, Melee::Response.text, Melee::Response.json, Melee::Response.redirect, Melee::Response.not_found, Melee::Response.forbidden, Melee::Response.error, Melee::Response.escape, Melee::Response#header, Melee::Response#with_header
  • Melee::HaltMelee::Halt#response
  • Melee::SessionMelee::Session#[], Melee::Session#[]=, Melee::Session#delete, Melee::Session#clear, Melee::Session#dirty?, Melee::Session#to_h, Melee::Session#csrf_token, Melee::Session#csrf_valid?
  • Melee::DBError
  • Melee::DBMelee::DB#query, Melee::DB#first, Melee::DB#run, Melee::DB#exec, Melee::DB#last_id, Melee::DB#transaction, Melee::DB#get, Melee::DB#put, Melee::DB#delete
  • Melee::HTTPMelee::HTTP.get, Melee::HTTP.post
  • Melee::HTTP::Error
  • Melee::HTTP::TimeoutError
  • Melee::HTTP::TooManyRedirects
  • Melee::HTTP::ResponseMelee::HTTP::Response#status, Melee::HTTP::Response#headers, Melee::HTTP::Response#body, Melee::HTTP::Response#url, Melee::HTTP::Response#ok?, Melee::HTTP::Response#json, Melee::HTTP::Response#header
  • Melee::LogMelee::Log#request_id, Melee::Log#debug, Melee::Log#info, Melee::Log#warn, Melee::Log#error, Melee::Log#exception, Melee::Log#with
  • DurableDurable#id, Durable#setup, Durable#on_timer, Durable#storage, Durable#timer, Durable#cancel_timer, Durable#destroy, Durable#log, Durable#release, Durable#live!
  • Durable::RemoteErrorDurable::RemoteError#remote_class
  • Durable::Destroyed
  • ConstantsHTTP

The top-level surface

Everything an app.rb, a file under lib/ or a template may call without a receiver.

Routes and filters

get

def get: (String pattern, ?csrf: bool) { () -> untyped } -> void

Declares a GET route; the block’s return value is the response. csrf: false exempts it from the check.

post

def post: (String pattern, ?csrf: bool) { () -> untyped } -> void

Declares a POST route.

put

def put: (String pattern, ?csrf: bool) { () -> untyped } -> void

Declares a PUT route.

patch

def patch: (String pattern, ?csrf: bool) { () -> untyped } -> void

Declares a PATCH route.

delete

def delete: (String pattern, ?csrf: bool) { () -> untyped } -> void

Declares a DELETE route.

before

def before: (?String prefix) { () -> untyped } -> void

Runs the block before any route whose path starts with prefix; halt or redirect in it ends the request.

not_found

def not_found: () { () -> untyped } -> void

Sets the body for responses to a path no route matched (404).

error

def error: () { (StandardError) -> untyped } -> void

Sets the body for responses to an uncaught exception (500); the block receives the exception.

title

def title: (String t) -> void

Names the app, for the default layout and the log.

app_title

def app_title: () -> String

The name given to title, or “” when none was set.

The current request

request

def request: () -> Melee::Request

The request being handled; only meaningful inside a route block or a filter.

params

def params: () -> Melee::Params

Path params, then query string, then form fields, later sources winning.

form

def form: () -> Melee::Params

Fields of a urlencoded request body, when the distinction from the query string matters.

query

def query: () -> Melee::Params

Query-string fields only, when the distinction from the body matters.

session

def session: () -> Melee::Session

The signed cookie session; values are Strings.

log

def log: () -> Melee::Log

The request’s logger, with the request id already attached.

db

def db: () -> Melee::DB

The app’s SQLite database, opened and migrated on first use.

Responses

redirect

def redirect: (String to) -> bot

Stops the request with a 303 to to; never returns.

back

def back: () -> String

The Referer header, or “/” when there is none; for redirect back.

halt

def halt: (?Integer status, ?String body, ?type: String?) -> bot

Stops the request with this status and body; never returns.

status

def status: (Integer code) -> void

Sets the status of the response the route is about to return.

def header: (String name, String value) -> void

Adds a header to the response the route is about to return.

json

def json: (untyped value, ?type: String?) -> Melee::Response

A JSON response (application/json unless type says otherwise) of any JSON-serialisable value.

text

def text: (String body, ?type: String?) -> Melee::Response

A text/plain response.

html

def html: (String body, ?type: String?) -> Melee::Response

A text/html response, the same as returning the String from the route.

Templates (generated per app by the build step from views/)

render

def render: (Symbol name, ?layout: bool, **untyped locals) -> String

Renders views/<name>.erb with the given locals, wrapped in views/layout.erb unless layout: false. A local the layout declares is forwarded to the layout as well; the generated signature names those keywords explicitly, so they arrive here in locals.

partial

def partial: (Symbol name, **untyped locals) -> String

Renders the partial views/_<name>.erb with the given locals.

h

def h: (untyped v) -> String

HTML-escapes a value; templates escape <%= %> already, so this is for HTML built by hand.

Strings, security and settings

url_encode

def url_encode: (String s) -> String

Percent-encodes a String for one path segment or one query value (spaces as %20).

url_decode

def url_decode: (String s) -> String

Decodes a percent-encoded String, turning “+” into a space.

csrf_token

def csrf_token: () -> String

The session’s CSRF token, created on first use.

csrf_field

def csrf_field: () -> String

A hidden _csrf input carrying the session’s token, for a form in a template.

secure_equal?

def secure_equal?: (String? a, String? b) -> bool

Constant-time String compare that tolerates nil on either side; for secrets and tokens.

random_token

def random_token: (?Integer bytes) -> String

A new URL-safe random token with bytes bytes of entropy (32 characters by default).

setting

def setting: (String | Symbol key) -> String?
def setting: (String | Symbol key, String value) -> String

Reads a value from the app’s key/value table (nil when unset), or writes one and returns it.

Melee

The objects the top-level surface hands back: the request, the response, params, the session, the database, the outbound HTTP client and the logger. Internals (Proto, Runtime, Native, Router, Current) are deliberately unsigned. Design: docs/design/ergonomics.md. Check with rbs -I stdlib/sig validate.

These signatures are also Spinel’s --rbs seeds, and a seed is trusted rather than checked: pinning a container to a storage kind Spinel did not infer makes the program read its own data back as garbage, with no diagnostic (docs/research/spinel.md; probe in spike/e-10-rbs-seeds). So scalars and nominal types are written exactly, but a Hash return carries the value type from spinel --emit-rbs on the unseeded build – Hash[String, String] only where inference already says so, Hash[String, untyped] otherwise, with the real values named in the comment – and a container-typed parameter is left untyped, since a caller can hand in any kind. A scalar parameter more than one Ruby type may reach is written as the union for the same reason: a seed narrower than the program converts at the call site with no diagnostic, so ?timeout: Integer over a Float had the callee see 0. A union of scalars is not pinned, it widens to the slow path, which is what an app build (no seeds) already does. Run stdlib/test/run.sh after changing one.

Melee.db

def self.db: () -> Melee::DB

The app’s database, opened and migrated on first use; the same object as the top-level db.

Melee.env

def self.env: (String name, ?String? default) -> String?

A configuration value set with melee env set NAME value, or default when it is unset or empty.

Melee::Params

A String-or-Symbol keyed view over one set of request parameters. Every value is a String.

Melee::Params#[]

def []: (String | Symbol key) -> String?

The value for this key, or nil when it was not sent.

Melee::Params#fetch

def fetch: (String | Symbol key, ?String default) -> String

The value for this key, or default (“” unless given) when it was not sent; never nil.

Melee::Params#key?

def key?: (String | Symbol key) -> bool

Whether this key was sent at all, including as an empty String.

Melee::Params#to_h

def to_h: () -> Hash[String, untyped]

The underlying name/value Hash; the values are Strings.

Melee::Params#each

def each: () { (String, String) -> void } -> void

Yields each name and value.

Melee::Params#empty?

def empty?: () -> bool

Whether no parameters were sent.

Melee::Request

One HTTP request. A request child handles exactly one, so the top-level helpers can read it directly.

Melee::Request#method

attr_reader method: String

The HTTP method, upper case (“GET”, “POST”, …).

Melee::Request#path

attr_reader path: String

The path, without the query string (“/admin/notes”).

Melee::Request#query

attr_reader query: String

The raw query string, without the “?” (“a=1&b=2”), “” when there is none.

Melee::Request#host

attr_reader host: String

The Host header.

Melee::Request#scheme

attr_reader scheme: String

“http” or “https”, as seen by melee-server.

Melee::Request#remote_addr

attr_reader remote_addr: String

The client’s IP address.

Melee::Request#headers

attr_reader headers: Array[[ String, String ]]

Every header as [name, value] pairs, in the order they arrived.

Melee::Request#body

attr_reader body: String

The raw request body; “” when there is none.

Melee::Request#log

attr_reader log: Melee::Log

This request’s logger, with the request id attached.

Melee::Request#id

attr_reader id: Integer

The request id melee-server gave this request; it appears in every log line.

Melee::Request#params

def params: () -> Hash[String, untyped]

Path params, then query string, then form fields, later sources winning; the values are Strings.

Melee::Request#path_params

def path_params: () -> Hash[String, untyped]

The params captured from the route pattern (“:id”, “*path”) only; the values are Strings.

Melee::Request#header

def header: (String name) -> String?

A header by name, case-insensitively; nil when it was not sent.

Melee::Request#content_type

def content_type: () -> String

The Content-Type header, or “” when there is none.

Melee::Request#base_url

def base_url: () -> String

Scheme and host, with no trailing slash (“https://kitchen.example”).

Melee::Request#get?

def get?: () -> bool

Whether this is a GET.

Melee::Request#post?

def post?: () -> bool

Whether this is a POST.

Melee::Request#query_params

def query_params: () -> Hash[String, String]

Query-string fields only.

Melee::Request#form

def form: () -> Hash[String, String]

Fields of a urlencoded body; {} for any other content type (multipart is not supported).

Melee::Request#json

def json: () -> untyped

The body parsed as JSON; raises JSON::ParserError when it is not JSON.

Melee::Request#cookies

def cookies: () -> Hash[String, String]

The cookies sent with the request, by name.

Melee::Request#session

def session: () -> Melee::Session

The signed cookie session, loaded on first use.

Melee::Request#env

def env: () -> Hash[String, untyped]

A Rack-compatible view of the request; “rack.input” is the body String, not an IO.

Melee::Request.url_encode

def self.url_encode: (String s) -> String

Percent-encodes a String for one path segment or one query value (spaces as %20).

Melee::Request.url_decode

def self.url_decode: (String s) -> String

Decodes a percent-encoded String, turning “+” into a space.

Melee::Response

A response: a status, headers and a body. A route may return one instead of a String.

Melee::Response#status

attr_reader status: Integer

The HTTP status.

Melee::Response#headers

attr_reader headers: Array[[ String, String ]]

The response headers as [name, value] pairs.

Melee::Response#body

attr_reader body: String

The response body.

Melee::Response.html

def self.html: (String body, ?status: Integer, ?headers: untyped, ?type: String?) -> Melee::Response

A text/html response; headers is a Hash of header name => value, type replaces the Content-Type.

Melee::Response.text

def self.text: (String body, ?status: Integer, ?headers: untyped, ?type: String?) -> Melee::Response

A text/plain response.

Melee::Response.json

def self.json: (untyped value, ?status: Integer, ?headers: untyped, ?type: String?) -> Melee::Response

An application/json response, generated from any JSON-serialisable value.

Melee::Response.redirect

def self.redirect: (String location, ?status: Integer) -> Melee::Response

A redirect, 303 unless another status is given.

Melee::Response.not_found

def self.not_found: (?String message) -> Melee::Response

A 404 with a plain-text body.

Melee::Response.forbidden

def self.forbidden: (?String message) -> Melee::Response

A 403 with a plain-text body.

Melee::Response.error

def self.error: (?String message) -> Melee::Response

A 500 with a plain-text body.

Melee::Response.escape

def self.escape: (String s) -> String

HTML-escapes &, <, >, “ and ’.

Melee::Response#header

def header: (String name) -> String?

A header by name, case-insensitively; nil when it is not set.

Melee::Response#with_header

def with_header: (String name, String value) -> Melee::Response

A copy of this response with one more header.

Melee::Halt

Raised by halt and redirect to stop the request; the dispatcher turns it back into a response.

Inherits StandardError.

Melee::Halt#response

attr_reader response: Melee::Response

The response to send instead of the route’s return value.

Melee::Session

The signed cookie session. Values are Strings; anything assigned is converted with to_s.

Melee::Session#[]

def []: (String | Symbol key) -> String?

The value stored under this key, or nil.

Melee::Session#[]=

def []=: (String | Symbol key, String? value) -> void

Stores a value under this key; assigning nil deletes it.

Melee::Session#delete

def delete: (String | Symbol key) -> void

Removes this key.

Melee::Session#clear

def clear: () -> void

Empties the session.

Melee::Session#dirty?

def dirty?: () -> bool

Whether the session changed during this request, and so a cookie will be set.

Melee::Session#to_h

def to_h: () -> Hash[String, untyped]

The session contents; every value written through the session is a String.

Melee::Session#csrf_token

def csrf_token: () -> String

This session’s CSRF token, created on first use.

Melee::Session#csrf_valid?

def csrf_valid?: (String? token) -> bool

Whether token matches this session’s CSRF token, compared in constant time.

Melee::DBError

Raised when SQLite reports an error.

Inherits StandardError.

Melee::DB

The app’s SQLite database. Migrations in db/migrations/*.sql are applied in name order on first use.

Melee::DB#query

def query: (String sql, *untyped binds) -> Array[Hash[String, untyped]]

Rows for a SELECT, each a Hash keyed by column name. A value is an Integer, a Float, a String or nil, following SQLite’s own types.

Melee::DB#first

def first: (String sql, *untyped binds) -> Hash[String, untyped]?

The first row of a SELECT, or nil when it returned none.

Melee::DB#run

def run: (String sql, *untyped binds) -> Integer

Runs an INSERT, UPDATE or DELETE and returns the number of rows it changed.

Melee::DB#exec

def exec: (String sql) -> void

Runs SQL that takes no bind values and returns no rows (DDL, PRAGMA).

Melee::DB#last_id

def last_id: () -> Integer

The rowid of the last INSERT on this connection.

Melee::DB#transaction

def transaction: () { () -> void } -> void

Runs the block in a transaction, rolling back and re-raising if it raises.

Melee::DB#get

def get: (String key) -> untyped

The value stored under this key by put, or nil when it was never set (storage.get, on a durable object’s database).

Melee::DB#put

def put: (String key, untyped value) -> untyped

Stores a JSON-shaped value under this key, creating the table on first use, and returns it.

Melee::DB#delete

def delete: (String key) -> bool

Removes this key; returns whether a row was deleted.

Melee::HTTP

The outbound HTTP client: GET and POST, with timeouts and up to five redirects. HTTP in an app.

Melee::HTTP.get

def self.get: (String url, ?query: untyped, ?headers: untyped, ?timeout: Integer | Float, ?raise_on_error: bool) -> Melee::HTTP::Response

Fetches a URL. query and headers are Hashes of name => value; raises Error or TimeoutError on failure, and on a 4xx/5xx with raise_on_error: true. timeout is seconds and is rounded up to a whole number, so a Float is taken but says nothing a whole number does not.

Melee::HTTP.post

def self.post: (String url, body: String, ?query: untyped, ?headers: untyped, ?timeout: Integer | Float, ?raise_on_error: bool) -> Melee::HTTP::Response

Posts a body to a URL; raises the same errors as get.

Melee::HTTP::Error

Raised for a transport failure, an unsupported URL, a body that is not JSON, or a 4xx/5xx with raise_on_error: true.

Inherits StandardError.

Melee::HTTP::TimeoutError

Raised when the connection or the read exceeded timeout seconds.

Inherits Melee::HTTP::Error.

Melee::HTTP::TooManyRedirects

Raised after five redirects.

Inherits Melee::HTTP::Error.

Melee::HTTP::Response

One HTTP response from HTTP.get or HTTP.post.

Melee::HTTP::Response#status

attr_reader status: Integer

The HTTP status.

Melee::HTTP::Response#headers

attr_reader headers: Array[[ String, String ]]

The response headers as [name, value] pairs.

Melee::HTTP::Response#body

attr_reader body: String

The response body.

Melee::HTTP::Response#url

attr_reader url: String

The URL the body finally came from, after any redirects.

Melee::HTTP::Response#ok?

def ok?: () -> bool

Whether the status is 2xx.

Melee::HTTP::Response#json

def json: () -> untyped

The body parsed as JSON; raises Melee::HTTP::Error when it is not JSON.

Melee::HTTP::Response#header

def header: (String name) -> String?

A header by name, case-insensitively; nil when it was not sent.

Melee::Log

Structured logging: one event per call, as key/value pairs, with the request id attached.

Melee::Log#request_id

attr_reader request_id: Integer

The id of the request this logger belongs to; 0 outside a request.

Melee::Log#debug

def debug: (String msg, **untyped fields) -> void

A debug event.

Melee::Log#info

def info: (String msg, **untyped fields) -> void

An informational event.

Melee::Log#warn

def warn: (String msg, **untyped fields) -> void

A warning.

Melee::Log#error

def error: (String msg, **untyped fields) -> void

An error.

Melee::Log#exception

def exception: (Exception e, **untyped fields) -> void

An error carrying an exception’s class and message (Spinel has no backtraces).

Melee::Log#with

def with: (**untyped extra) -> Melee::Log

A copy of this logger with extra fields attached to every event it writes.

Durable

The base class of a durable object (docs/design/persistent.md, objects.md): a named, long-lived object with its own SQLite database and one timer, hosted by the app’s worker process. Apps never construct or call these directly; the build step generates Klass.get(id) and a Handle per subclass, which is why no signature is written for a generated Handle here.

Durable#id

attr_reader id: String

This object’s own id, given by Klass.get(id).

Durable#setup

def setup: () -> void

Called once, inside the call that first created the object, before that call’s own method runs.

Durable#on_timer

def on_timer: () -> void

Called when the pending timer fires.

Durable#storage

def storage: () -> Melee::DB

This object’s own SQLite database, opened (and migrated) on first use.

Durable#timer

def timer: (?after: Integer, ?at: Integer | Time) -> Integer

Sets the one pending timer, replacing any previous one, and returns it as Unix seconds.

Durable#cancel_timer

def cancel_timer: () -> void

Clears the pending timer, if any.

Durable#destroy

def destroy: () -> void

Deletes the object’s database and its registry row; storage, timer and cancel_timer raise Durable::Destroyed if called again in the same call.

Durable#log

def log: () -> Melee::Log

A logger tagged with this object, since no request is current in the worker.

Durable#release

def release: () -> void

Closes the storage handle when the worker drops this instance; the next storage call reopens it.

Durable#live!

def live!: () -> void

Raises Durable::Destroyed if this object was already destroyed earlier in this call.

Durable::RemoteError

Raised in the caller when a durable method raised inside the worker, or the worker could not be reached.

Inherits StandardError.

Durable::RemoteError#remote_class

attr_reader remote_class: String

The raising exception’s class name, or “Melee::Objects::WorkerError” when the worker could not be reached at all.

Durable::Destroyed

Raised by storage, timer and cancel_timer after destroy in the same call.

Inherits StandardError.

Constants

HTTP

HTTP: singleton(Melee::HTTP)

HTTP in an app is Melee::HTTP: HTTP.get(url, timeout: 10).