{"id":13769328,"url":"https://github.com/coderofsalvation/soakbean","last_synced_at":"2025-04-12T20:09:52.042Z","repository":{"id":146965588,"uuid":"427642747","full_name":"coderofsalvation/soakbean","owner":"coderofsalvation","description":"Write beautiful ~2.3MB redbean (docker) apps using (redbean) plug-and-play middleware. #tiniest_fastest_server_in_the_universe","archived":false,"fork":false,"pushed_at":"2024-01-05T10:30:39.000Z","size":3664,"stargazers_count":14,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-12T20:09:44.943Z","etag":null,"topics":["crossplatform","express","fast","lua","microstack","webserver"],"latest_commit_sha":null,"homepage":"","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/coderofsalvation.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2021-11-13T11:11:11.000Z","updated_at":"2025-01-10T14:01:23.000Z","dependencies_parsed_at":"2024-01-12T10:26:48.563Z","dependency_job_id":null,"html_url":"https://github.com/coderofsalvation/soakbean","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coderofsalvation%2Fsoakbean","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coderofsalvation%2Fsoakbean/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coderofsalvation%2Fsoakbean/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coderofsalvation%2Fsoakbean/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/coderofsalvation","download_url":"https://codeload.github.com/coderofsalvation/soakbean/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248625493,"owners_count":21135513,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["crossplatform","express","fast","lua","microstack","webserver"],"created_at":"2024-08-03T17:00:22.070Z","updated_at":"2025-04-12T20:09:52.016Z","avatar_url":"https://github.com/coderofsalvation.png","language":"Lua","readme":"\u003cimg src=\".dtp/soakbean.jpg\"/\u003e\n\n## Reactive plugnplay middleware for redbean\n\nWrite beautiful ~2.3MB [redbean (docker) apps](https://redbean.dev) like this [.init.lua](src/.init.lua):\n\n## Beautiful micro stack\n\n\u003cimg src=\".dtp/soakbean.gif\"\u003e\n\n* re-use middleware functions across redbean projects\n* reactive programming (write less code)\n* easy express-style routing\n* easily adapt to redbean API changes\n\n## Syntactic sugar \n\n```lua\napp = require(\"soakbean\") {\n  bin = \"./soakbean.com\",\n  opts = { my_cli_arg=0 },\n  cmd={\n    -- runtask =  {file=\"sometask.lua\",   info=\"description of cli cmd\"}\n  },\n  title     = 'SOAKBEAN - a buddy of redbean',\n}\n\napp.url['^/data']   = '/data.lua'          -- setup custom file endpoint\n                                           --\napp.get('^/', app.template('index.html') ) -- alias for app.tpl( LoadAsset('index.html'), app )\n                                           -- also see app.post app.put and so on\napp                                        --\n.use( require(\"json\").middleware() )       -- try plug'n'play json API middleware \n.use( app.router( app.url ) )              -- try url router\n.use( app.response() )                     -- try serve app response  (if any)\n.use( function(req,next) Route() end)      -- fallback default redbean fileserver\n\nfunction OnHttpRequest() app.run() end\n```\n\nJust run it straight from the repository using [redbean.com](https://redbean.dev) itself:\u003cbr\u003e\n\n```\n$ git clone https://github.com/coderofsalvation/soakbean \u0026\u0026 cd src\n$ redbean.com -D . --my-cli-arg=abc\n```\n\nThen you can easily package the current directory into your own (renamed redbean) COM-file:\n\n```\n$ sed -i 's/NAME=soakbean/NAME=yourapp/g'\n$ ./make all\n$ ./yourapp.com --my-cli-arg=abc\n```\n\n\u003e Profit!\n\n\n## Getting started \n\n| Lazy | Recommended | Docker |\n|-|-|-|\n| download [soakbean.com](https://github.com/coderofsalvation/soakbean/raw/master/soakbean.com), add html (and/or lua) files using a zip-filemanager, and run `./soakbean.com` | download [redbean.com](https://redbean.dev) 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` |\n\n\u003e middleware: copy [middleware](middleware) functions to `src/.lua`-folder where needed\n\n## Cute simple backend\u003c-\u003efrontend traffic\n\nJust look at how cute this [index.html](src/index.html) combines serverside templating with RESTful \u0026 DOM-reactive templating:\n\n```\n\u003ctitle\u003e${title}\u003c/title\u003e                  \u003c-- evaluated serverside                           --\u003e\n\u003cspan x-text=\"$store.app.time\"/\u003e         \u003c-- evaluated clientside                           --\u003e\n\u003cspan x-text=\"$store.app.title\"/\u003e        \u003c-- evaluated clientside using REST call to server --\u003e\n \n```\n\n\n## Middleware functions\n\nYou can easily manipulate the http-request flow, using existing middleware functions:\n\n```lua\napp.use( \n    require(\"blacklisturl\")({\n        \"^/secret/\",\n        \"^/me-fainting-next-to-justinbieber.mp4\"\n    })\n)\n```\n\n\u003e make sure you copy [middleware/blacklisturl.lua](middleware/blacklisturl.lua) to [src/.lua](src/.lua)\n\nor just write ad-hoc middleware:\n\n```lua\napp.use( function(req,res,next)\n  res.status(200)\n  res.header('content-type','text/html')\n  res.body('hello world')\n  next() -- comment this to prevent further middleware altering body, status headers e.g. \nend)\n```\n\n```lua\napp.use( function(req,res,next)\n    if !req.loggedin \u0026\u0026 req.url:match(\"^/mydata\") then\n       res.status(403)\n    else next()\nend)\n```\n\n\n\u003e WANTED: please contribute your [middleware](middleware) functions by pushing repositories with nameconvention `soakbean-middleware-\u003cname\u003e`. Everybody loves (re)using battle-tested middleware.\n\n## req \u0026 res object\n\n| key | type | alias for redbean |\n|-|-|-|\n| `req.method` | string | `GetMethod()` |\n| `req.url` | string | `GetPath()` |\n| `req.param` | table | `GetParams()` |\n| `req.host` | string | `GetHost()` |\n| `req.header` | table | `GetHeaders()` |\n| `req.protocol` | string | `GetScheme()` |\n| `req.body` | table or string |  |\n| `res.body(value)` | string | `Write(value) including auto-encoding (json e.g.)` |\n| `res.status(code)` | int | `SetStatus(code)` |\n| `res.header(type,value)` | string,string | `SetHeader(type,value)` |\n\n## Simple template evaluation\n\nindex.html\n```\n\u003ctitle\u003e${title}\u003c/title\u003e\n```\n\nlua\n```\napp.title = \"hello world\"\napp.get('^/', app.template('index.html') ) \n```\n\n\u003e NOTE: this is basically serving the output of `app.tpl( LoadAsset('index.html'), app )` \n\n## Reactive programming\n\n#### react to variable changes:\n\n```lua\napp.on(\"foo\", function(k,v)\n  print(\"appname changed: \" .. v)\nend)\n\napp.foo = \"flop\"   -- output: appname changed: flop\napp.foo = \"bar\"    -- output: appname changed: bar\n```\n\n#### react to function calls \n\n```lua \napp.on('foobar', function(a)\n    print(\"!\")\nend)\n\napp.foobar = function(a)\n    print('foobar')\nend\n\napp.foobar()       -- output: foobar!\n```\n\n#### react to router patterns\n\n```lua\napp.url['^/foo'] = '/somefile.lua'\n\napp.on('^/foo', function(a,b)\n  -- do something\nend)\n```\n\n#### react to luafile endpoint execution \n\n```lua\napp.url['^/foo'] = '/somefile.lua'\n\napp.on('somefile.lua', function(a,b)\n  -- do something\nend)\n```\n\n#### react to response code/header/body changes\n\n```lua\napp.on('res.status', print )\napp.on('res.body'  , print )\napp.on('res.header', function(k,v)\n  print(k .. \" =\u003e \" .. v)\nend)\n```\n\n\u003e NOTE: above is handy for debugging a flow. Use `app.use(..)` for more control.\n\n## Roadmap / Scope\n\n* scope is backend, not frontend\n* http auth (*)\n* middleware: sqlite user sessions (*)\n* middleware: sqlite tiny job queue (*)\n* middleware: sqlite tiny rule engine (*)\n* middleware: sqlite CRUD middleware (endpoints + sqlite schema derived from jsonschema) (*)\n\n\\* = please contribute! =]\n","funding_links":[],"categories":["Redbean"],"sub_categories":["Projects"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoderofsalvation%2Fsoakbean","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcoderofsalvation%2Fsoakbean","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoderofsalvation%2Fsoakbean/lists"}