Home

Awesome

<img src=".dtp/soakbean.jpg"/>

Reactive plugnplay middleware for redbean

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

Beautiful micro stack

<img src=".dtp/soakbean.gif">

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:<br>

$ 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

LazyRecommendedDocker
download soakbean.com, add html (and/or lua) files using a zip-filemanager, and run ./soakbean.comdownload 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

keytypealias for redbean
req.methodstringGetMethod()
req.urlstringGetPath()
req.paramtableGetParams()
req.hoststringGetHost()
req.headertableGetHeaders()
req.protocolstringGetScheme()
req.bodytable or string
res.body(value)stringWrite(value) including auto-encoding (json e.g.)
res.status(code)intSetStatus(code)
res.header(type,value)string,stringSetHeader(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

* = please contribute! =]