ilusm.dev

be

Backend framework - app config, route dispatch, HTTP server startup, request/response helpers, logging and CORS middleware, in-memory and Redis caching.

Load with: use be

What this module does

be is a thin backend framework that wraps srv (the raw HTTP server) with a route table, middleware chain, error handling, request parsing, and response shortcuts. You create an app config with bene, define routes with bead/beps/etc., then call beru to start the server.

All registered routes and middleware are stored in the app config object. Each request is matched against the route table (exact method + path match), wrapped in error handling, and optionally logged. If no route matches, a 404 is returned.

All functions are also accessible as properties of the be object.

Quick example

use be

app = bene({
    port: 3000,
    middleware: [belg1(), becr1()]
})

app.rt = trl.cat(app.rt, [
    bead("/",       \(rq, rs, ap) beok(rs, {msg: "hello"})),
    beps("/echo",   \(rq, rs, ap) beok(rs, bejs(rq))),
    benf1: bead("/404", \(rq, rs, ap) benf(rs))
])

beru(app)

Functions

App setup and server

bene(op) / be.bemk(op)

Creates an app config object from an options object. Reads: routes (list, default []), middleware (list, default []), error_handler (function, default been), logger (bool, default tru), port (int, default 8080), db and cache (both default nil).

beru(ap) / be.beus(ap)

Starts the HTTP server on 127.0.0.1:{port}. Registers all middleware via srv.srvus, sets the dispatch handler, logs the startup, and calls srv.srvru.

been(rq, rs, er)

The default error handler. Logs the error, sets status 500, and responds with {er: error_string} as JSON.

belg(rq)

Logs the HTTP method and path of a request using obs.obslg.

Route helpers

Each returns a route descriptor {mt, pt, hd} - method, path, and handler function.

bead(pt, hd) / be.bead(pt, hd)

GET route.

beps(pt, hd) / be.beps(pt, hd)

POST route.

bepu(pt, hd) / be.bepu(pt, hd)

PUT route.

bede(pt, hd) / be.bede(pt, hd)

DELETE route.

bepa(pt, hd) / be.bepa(pt, hd)

PATCH route.

Request helpers

bejs(rq) / be.bejs(rq)

Parses the request body as JSON. Errors with "be.js: invalid JSON: ..." if parsing fails.

bepa1(rq) / be.bepa1(rq)

Parses query parameters from the request URL (the ?key=value&... portion). Returns an object with URL-decoded keys and values.

behd(rq, nm) / be.behd(rq, nm)

Reads a request header by name via srv.srqhd.

Response helpers

beok(rs, bd) / be.beok(rs, bd)

200 OK. If bd is an object or list, responds with JSON. Otherwise responds with the string value.

becr(rs, bd) / be.becr(rs, bd)

201 Created. Same JSON/string logic as beok.

bebd(rs, er) / be.bebd(rs, er)

400 Bad Request with {er: error_string} JSON body.

beun(rs) / be.beun(rs)

401 Unauthorized - status only, no body.

beau(rs, bd) / be.beau(rs, bd)

403 Forbidden with {er: "Forbidden", dt: bd} JSON body.

benf(rs) / be.benf(rs)

404 Not Found - status only.

bese(rs, er) / be.bese(rs, er)

500 Internal Server Error with {er: error_string} JSON body.

Middleware

belg1() / be.belg1()

Returns a logging middleware function that logs the timestamp, method, and path of every request via obs.obslg, then calls next.

becr1() / be.becr1()

Returns a CORS middleware function. Sets Access-Control-Allow-Origin: *, allowed methods (GET, POST, PUT, DELETE, OPTIONS), and allowed headers (Content-Type, Authorization). Responds 200 to OPTIONS preflight requests and calls next for all others.

Caching

becne(tp, op) / be.becne(tp, op)

Creates a cache. tp is "redis" (connects to op.host, default "localhost:6379") or "memory" (stores in a plain object with per-key expiry timestamps). Errors on unknown types.

becgt(ca, ky) / be.becgt(ca, ky)

Gets a cached value by key. For Redis delegates to redis.redgt. For memory, checks the expiry timestamp and returns nil if expired.

becst(ca, ky, vl, ex) / be.becst(ca, ky, vl, ex)

Sets a value with an expiry. ex is seconds for Redis; converted to milliseconds for in-memory. For Redis delegates to redis.redst.

Database stubs

bdbne(tp, cn) / be.bdbne(tp, cn)

Creates a database config object with type and connection string. Not yet connected.

bdbco(db) / be.bdbco(db)

Returns the database config unchanged. Connection is a stub - not yet implemented.

bdbqu(db, qu, pr) / be.bdbqu(db, qu, pr)

Query stub - returns nil. Not yet implemented.

Notes

  • Route matching is exact - method and full path (query string stripped) must match. There is no wildcard or parameterised routing in the current dispatch loop.
  • Database functions (bdbne, bdbco, bdbqu) are stubs and do not execute queries.
  • Requires trl, txt, srv, net, jsn, obs, redis, and tim.
  • All functions are also accessible via the be object: be.bemk, be.beus, be.bead, etc.