Reference · Files and processes

files

signature
files(str, str | null=, map | null=) -> response

What it does

A folder of files served as a static host serves it, for a route to answer with: route GET /*path = files("site", path). The first argument is the folder, under the program's folder; the second is the path asked for, as the route's rest parameter gives it. A folder's index.html answers for the folder (/ and /docs/), a path with no extension finds the file with .html added (/about is about.html), a folder named without its / is redirected to it with a 301 (/docs to /docs/, its query kept), and a path that finds nothing gets the folder's 404.html with the status 404. Each file goes out as file() sends it: its type from the extension, an ETag, Last-Modified, ranges, and nothing added to it. The options map takes index (the file a folder is answered with), extensions (the ones tried for a path that has none), not_found (the page for a miss, or null for the plain 404) and cache, as file() takes it.

quillo serve site runs the same as a program of its own: one route, files(".", path), over the folder, with the options of quillo run, read as run reads them. Its URLs are its own, so a file asked for with a / after it (/a.txt/, /about/) is moved to its path without one (301, cache-control: max-age=3600), only when it would be served there. In a route, files() serves what it is asked for: a.txt/ is a.txt, so a site whose URLs end in / keeps them.

Examples

in a program
route GET /*path = files("site", path)route GET /docs/*path = files("manual", path, { cache: "1h" })route GET /app/*path = files("dist", path, { index: "home.htm", extensions: ["htm"], not_found: null })

Outside a request it can be looked at like any response:

write_file("site/index.html", "<p>home</p>")?write_file("site/about.html", "<p>about</p>")?write_file("site/docs/index.html", "<p>docs</p>")?write_file("site/404.html", "<p>no such page</p>")?print(files("site", "").body, files("site", "about").body, files("site", "docs/").body)let miss = files("site", "nothing")print(miss.status, miss.body, miss.headers["etag"])print(files("site", "about.html", { cache: "1h" }).headers["cache-control"])
output
<p>home</p> <p>about</p> <p>docs</p>404 <p>no such page</p> nullpublic, max-age=3600, immutable

Edge cases

write_file("site/about.html", "<p>about</p>")?write_file("site/notes.md", "# Notes")?write_file("site/404.html", "<p>no such page</p>")?print(files("site", "about", { extensions: [] }).status, files("site", "nothing", { not_found: null }).body)print(files("site", "notes.md").headers["content-type"])print(files("site", "../main.qwe").status)print(files("site", "nothing", { cache: "1y" }).headers["cache-control"], files("site", "about.html/").status)db.open("site/app.db")db.exec("create table t (x)")print(files("site", "app.db").status, file("site/app.db").status)
output
404 not foundtext/markdown; charset=utf-8404no-cache 200404 200

Errors

An option it does not take, an index that is not a file name, extensions that is not a list, or options that are not a map, are runtime errors, not error values.

this one fails
print(files("site", "a", { nope: 1 }))
output
line 1: `files` has no option `nope`: it takes `index`, `extensions`, `not_found` and `cache`
this one fails
print(files("site", "a", { index: 3 }))
output
line 1: `files`'s index is a file name, got 3

Chaining

It answers a route, with the rest of the path given to it:

in a program
route GET /*path = path | (p) => files("public", p)

See also

file, respond, markdown_page, redirect

Thread
1Useful? Like it, or add to its thread below.

Thread 0 posts

On files(): questions, tips, corrections, and code that uses it.

No posts yet. The first one opens the thread.

    Edit this page on GitHub · every example's output was made by running it (tools/refcheck.mjs) · questions on Discord or r/quillo