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 filters —
get,post,put,patch,delete,before,not_found,error,title,app_title - The current request —
request,params,form,query,session,log,db - Responses —
redirect,back,halt,status,header,json,text,html - Templates (generated per app by the build step from views/) —
render,partial,h - Strings, security and settings —
url_encode,url_decode,csrf_token,csrf_field,secure_equal?,random_token,setting - Melee —
Melee.db,Melee.env - Melee::Params —
Melee::Params#[],Melee::Params#fetch,Melee::Params#key?,Melee::Params#to_h,Melee::Params#each,Melee::Params#empty? - Melee::Request —
Melee::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::Response —
Melee::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::Halt —
Melee::Halt#response - Melee::Session —
Melee::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::DB —
Melee::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::HTTP —
Melee::HTTP.get,Melee::HTTP.post - Melee::HTTP::Error
- Melee::HTTP::TimeoutError
- Melee::HTTP::TooManyRedirects
- Melee::HTTP::Response —
Melee::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::Log —
Melee::Log#request_id,Melee::Log#debug,Melee::Log#info,Melee::Log#warn,Melee::Log#error,Melee::Log#exception,Melee::Log#with - Durable —
Durable#id,Durable#setup,Durable#on_timer,Durable#storage,Durable#timer,Durable#cancel_timer,Durable#destroy,Durable#log,Durable#release,Durable#live! - Durable::RemoteError —
Durable::RemoteError#remote_class - Durable::Destroyed
- Constants —
HTTP
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.
header
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).