Skip to content
LexerLangv0.1.0

Request and response

http_request, form and JSON bodies, headers, cookies and isolation.

Once $app.listen starts listening, the page no longer runs once but on every request:

Text
request
  ↓
the file runs from the top   (from the AST cache; reparsed if the file changed)
  ↓
$req = new http_request      → that request's object
  ↓
the document is built
  ↓
SSR → minify → gzip → response
LexerLang
use http_request

$req = new http_request

if $req.method == http_request.types.POST then
    out($req.form_data.name)
end if

What can be read#

CallReturns
$req.method"GET" / "POST" / …
$req.paththe request path
$req.content_typee.g. "application/json" (parameters stripped)
$req.form_dataform fields object
$req.jsonthe decoded JSON body, or null
$req.dataPOST data regardless of body format
$req.queryquery parameters object
$req.headersheaders object (names lowercased)
$req.bodythe raw body
$req.form("name")the field, or null
$req.get("q")the query parameter, or null
$req.header("accept")the header, or null
$req.is("POST")case-insensitive comparison

The http_request.types table: GET POST PUT DELETE PATCH HEAD OPTIONS.

Object or helper#

$req.form_data.name raises an error when the field is absent, so that a typo does not pass silently. For optional fields use $req.form("name"), which returns null.

Body formats#

Content-TypeWhere it lands
application/x-www-form-urlencodedform_data and data
multipart/form-dataform_data and data (text fields)
application/jsonjson and data

Parameters such as ; charset=utf-8 are ignored. Malformed JSON does not crash the page; json becomes null.

JSON is converted into the language's own values: object → object, array → array, number → int/float, true/falsebool, nullnull.

LexerLang
$j = $req.json
out($j.get("user").get("name"))
out($j.get("tags").get(0))

Escaping#

Form data is not raw HTML; it is escaped on the way into the document. Sending name=<script> does not open a tag.

Isolation#

Every request lives in its own run; one request's variables do not leak into another. Concurrent requests do not affect each other. Pages included with from_file see the current request too.

new http_request returns an empty GET request when there is no request context, so a page can also be run from the console.

Accepted methods are GET HEAD POST PUT DELETE PATCH in dynamic mode, and GET HEAD only in static mode.

File uploads#

HTML
<form method="POST" enctype="multipart/form-data">
    <input type="file" name="document">
</form>
LexerLang
$file = $req.files("document")

if $file != null then
    $file.save(path.pwd + "/uploads/" + $file.uuid + "." + $file.extension)
end if
Field / callMeaning
$file.namethe submitted name — the path part is stripped
$file.safe_namea name suitable for writing to disk
$file.uuida unique identifier per upload
$file.sizebytes
$file.mime_typethe type — determined from the content
$file.extensionthe extension, without the dot
$file.image{type, width, height} for images, otherwise null
$file.contentbinary content
$file.save($path)writes to disk, creating the directory if needed

Do not use the submitted name when writing to disk. uuid also stops two users submitting the same name from overwriting each other's files. The original name remains available as $file.name and can be kept as metadata.

The type is read from the content, not from the header the client declared; that header comes from the user and can be changed. The submitted name is untrusted (../../etc/passwd); only the last segment is taken. The body limit is 10 MB.

Image processing#

LexerLang
$image = fs.image($file.content)
$image.resize({width: 800}).to_jpeg({quality: 80}).save($path)

Formats read and written: JPEG, PNG, GIF. to_webp(...) does not exist yet.

Next#

Calling other services.