Skip to content

Latest commit

 

History

History
214 lines (156 loc) · 5.63 KB

README.md

File metadata and controls

214 lines (156 loc) · 5.63 KB

Reactive plugnplay middleware for redbean

Write beautiful ~2.3MB redbean (docker) apps like this .init.lua:

Beautiful micro stack

  • re-use middleware functions across redbean projects
  • reactive programming (write less code)
  • easy express-style routing
  • easily adapt to redbean API changes

Syntactic sugar

app = require("soakbean") {
  bin = "./soakbean.com",
  opts = { my_cli_arg=0 },
  cmd={
    -- runtask =  {file="sometask.lua",   info="description of cli cmd"}
  },
  title     = 'SOAKBEAN - a buddy of redbean',
}

app.url['^/data']   = '/data.lua'          -- setup custom file endpoint
                                           --
app.get('^/', app.template('index.html') ) -- alias for app.tpl( LoadAsset('index.html'), app )
                                           -- also see app.post app.put and so on
app                                        --
.use( require("json").middleware() )       -- try plug'n'play json API middleware 
.use( app.router( app.url ) )              -- try url router
.use( app.response() )                     -- try serve app response  (if any)
.use( function(req,next) Route() end)      -- fallback default redbean fileserver

function OnHttpRequest() app.run() end

Just run it straight from the repository using redbean.com itself:

$ git clone https://github.com/coderofsalvation/soakbean && cd src
$ redbean.com -D . --my-cli-arg=abc

Then you can easily package the current directory into your own (renamed redbean) COM-file:

$ sed -i 's/NAME=soakbean/NAME=yourapp/g'
$ ./make all
$ ./yourapp.com --my-cli-arg=abc

Profit!

Getting started

Lazy Recommended Docker
download soakbean.com, add html (and/or lua) files using a zip-filemanager, and run ./soakbean.com download redbean.com and run it in the src folder of this repo (see above cmdline) clone this repo and run ./make docker and surf to http://localhost:8080

middleware: copy middleware functions to src/.lua-folder where needed

Cute simple backend<->frontend traffic

Just look at how cute this index.html combines serverside templating with RESTful & DOM-reactive templating:

<title>${title}</title>                  <-- evaluated serverside                           -->
<span x-text="$store.app.time"/>         <-- evaluated clientside                           -->
<span x-text="$store.app.title"/>        <-- evaluated clientside using REST call to server -->
 

Middleware functions

You can easily manipulate the http-request flow, using existing middleware functions:

app.use( 
    require("blacklisturl")({
        "^/secret/",
        "^/me-fainting-next-to-justinbieber.mp4"
    })
)

make sure you copy middleware/blacklisturl.lua to src/.lua

or just write ad-hoc middleware:

app.use( function(req,res,next)
  res.status(200)
  res.header('content-type','text/html')
  res.body('hello world')
  next() -- comment this to prevent further middleware altering body, status headers e.g. 
end)
app.use( function(req,res,next)
    if !req.loggedin && req.url:match("^/mydata") then
       res.status(403)
    else next()
end)

WANTED: please contribute your middleware functions by pushing repositories with nameconvention soakbean-middleware-<name>. Everybody loves (re)using battle-tested middleware.

req & res object

key type alias for redbean
req.method string GetMethod()
req.url string GetPath()
req.param table GetParams()
req.host string GetHost()
req.header table GetHeaders()
req.protocol string GetScheme()
req.body table or string
res.body(value) string Write(value) including auto-encoding (json e.g.)
res.status(code) int SetStatus(code)
res.header(type,value) string,string SetHeader(type,value)

Simple template evaluation

index.html

<title>${title}</title>

lua

app.title = "hello world"
app.get('^/', app.template('index.html') ) 

NOTE: this is basically serving the output of app.tpl( LoadAsset('index.html'), app )

Reactive programming

react to variable changes:

app.on("foo", function(k,v)
  print("appname changed: " .. v)
end)

app.foo = "flop"   -- output: appname changed: flop
app.foo = "bar"    -- output: appname changed: bar

react to function calls

app.on('foobar', function(a)
    print("!")
end)

app.foobar = function(a)
    print('foobar')
end

app.foobar()       -- output: foobar!

react to router patterns

app.url['^/foo'] = '/somefile.lua'

app.on('^/foo', function(a,b)
  -- do something
end)

react to luafile endpoint execution

app.url['^/foo'] = '/somefile.lua'

app.on('somefile.lua', function(a,b)
  -- do something
end)

react to response code/header/body changes

app.on('res.status', print )
app.on('res.body'  , print )
app.on('res.header', function(k,v)
  print(k .. " => " .. v)
end)

NOTE: above is handy for debugging a flow. Use app.use(..) for more control.

Roadmap / Scope

  • scope is backend, not frontend
  • http auth (*)
  • middleware: sqlite user sessions (*)
  • middleware: sqlite tiny job queue (*)
  • middleware: sqlite tiny rule engine (*)
  • middleware: sqlite CRUD middleware (endpoints + sqlite schema derived from jsonschema) (*)

* = please contribute! =]