class
Analyzer::Gleam::Wisp
- Analyzer::Gleam::Wisp
- Analyzer
- Reference
- Object
Overview
Wisp has no route table — routing is a case over the split path,
and the verb comes either from a second subject in the same case or
from the handler it delegates to. All four shapes are common in real
apps:
case wisp.path_segments(req) { # path only
["users", id] -> user(req, id)
}
case wisp.path_segments(req), req.method { # path, method
["api", "teams"], http.Post -> create_team(req)
}
case req.method, wisp.path_segments(req) { # method, path
Get, ["members"] -> members.list(req)
}
let path = wisp.path_segments(req) # via let bindings
let method = req.method
case method, path {
Get, [] -> home.render(req)
}
Rather than assume an order, the subject is parsed to learn which
comma position holds the path and which holds the method, and each
arm is then read against those positions. When the arm carries no
verb the handler it calls is followed (resolve_handler) to find a
case req.method or a wisp.require_method.
Defined in:
analyzer/analyzers/gleam/wisp.crConstant Summary
-
BODY_VERBS =
Set {"POST", "PUT", "PATCH", "ANY"} -
Verbs that can carry a request body.
-
CALL_REGEX =
/(?:\b([a-z_][A-Za-z0-9_]*)\s*\.\s*)?\b([a-z_][A-Za-z0-9_]*)\s*\(/ -
CASE_KEYWORD =
/\bcase\b/ -
COOKIE_REGEX =
/wisp\.get_cookie\s*\(\s*[^,]+,\s*"([^"]+)"/ -
FORM_FIELD_REGEX =
/key_find\s*\(\s*[A-Za-z_][A-Za-z0-9_]*\.(?:values|files)\s*,\s*"([^"]+)"/ -
list.key_find(formdata.values, "title")— the binder is namedformdata,form, … so match any receiver. -
FORM_REGEX =
/wisp\.require_form\s*\(/ -
FUNCTION_DEF =
/^\s*(?:pub\s+)?fn\s+([a-z_][A-Za-z0-9_]*)\s*\(/ -
HEADER_REGEX =
/\bget_header\s*\(\s*(?:[^,"()]+,\s*)?"([^"]+)"/ -
2-arg
request.get_header(req, "accept")and the piped 1-arg|> request.get_header("accept")are both idiomatic. -
HTTP_METHODS =
{"Get" => "GET", "Post" => "POST", "Put" => "PUT", "Patch" => "PATCH", "Delete" => "DELETE", "Head" => "HEAD", "Options" => "OPTIONS", "Trace" => "TRACE", "Connect" => "CONNECT"} -
IGNORED_CALL_MODULES =
Set {"wisp", "gleam", "http", "request", "response", "io", "list", "string", "int", "float", "result", "option", "json", "dict", "bool", "bit_array", "dynamic", "decode", "uri", "bytes_tree", "string_tree", "mist", "case", "fn", "use", "let"} -
Calls into the standard library and wisp itself are responses and helpers, never route handlers.
-
IMPORT_LINE =
/^\s*import\s+([a-z_][A-Za-z0-9_\/]*)(?:\s*\.\s*\{[^}]*\})?(?:\s+as\s+([a-z_][A-Za-z0-9_]*))?/ -
JSON_FIELD_REGEX =
/\bfield\s*\(\s*"([^"]+)"/ -
A
wisp.require_jsonbody is decoded elsewhere;decode.fieldis where the field names actually appear. -
JSON_REGEX =
/wisp\.require_json\s*\(/ -
MAX_RESOLVE_DEPTH =
3 -
Depth limit for following a route arm through handler functions to the
case req.methodthat names its verb. -
MAX_SUBJECT_LINES =
8 -
A
casesubject spans at most a handful of lines even when the formatter wraps it. -
METHOD_BINDING =
/\blet\s+([a-z_][A-Za-z0-9_]*)\s*=\s*[a-z_][A-Za-z0-9_]*\.method\b/ -
METHOD_CASE =
/\bcase\s+[A-Za-z_][A-Za-z0-9_]*\.method\s*\{/ -
METHOD_SOURCE =
/\.method\b/ -
METHOD_TOKEN =
/\A(?:[a-z_][A-Za-z0-9_]*\.)?([A-Z][A-Za-z0-9_]*)\z/ -
NON_ROUTE_BODY =
/\A\s*(?:wisp\.)?(?:method_not_allowed|not_found|bad_request|unprocessable_entity|internal_server_error|handle_request\s*\(\s*\))/ -
_ -> wisp.method_not_allowed([Get, Post])and_, _ -> wisp.not_found()are the fallthrough arms every wisp router ends with. They match a path but serve no endpoint. -
PATH_BINDING =
/\blet\s+([a-z_][A-Za-z0-9_]*)\s*=[^\n]*\bpath_segments\s*\(/ -
let path = wisp.path_segments(req)/let method = req.method. Apps that bind these before thecasewould otherwise leave the subject looking like two bare identifiers. -
PATH_SOURCE =
/\bpath_segments\s*\(/ -
REQUIRE_METHOD =
/require_method\s*\(\s*[^,)]+,\s*(?:[a-z_][A-Za-z0-9_]*\.)?([A-Z][A-Za-z0-9_]*)/ -
SERVE_STATIC =
/wisp\.serve_static\s*\(/ -
STRING_BODY =
/wisp\.require_(?:string|bit_array)_body\s*\(/