Lapis v1.8.1 — composite foreign keys, better docs, and more: changelog

What is it? Lapis is a framework for building web applications using MoonScript or Lua that runs inside of a customized version of Nginx called OpenResty. Want to talk Lapis? Join our Discord

Lua View examples in MoonScript MoonScript View examples in Lua

local lapis = require "lapis" local app = lapis . Application () app : match ( "/" , function ( self ) return "Hello world!" end ) return app lapis = require " lapis " class extends lapis . Application " / " : => " Hello world! "

How does it work? Lua is run directly inside of the Nginx worker, giving you the smallest barrier between the webserver and your code. OpenResty executes your Lua/MoonScript with LuaJIT, so it’s blazing fast. Have a look at Web Framework Benchmarks just to see how OpenResty stacks up against other platforms. Nginx’s event loop is used for all asynchronous actions, including HTTP requests and database queries. With the power of Lua coroutines code is written synchronously but runs asynchronously, without all that callback spaghetti seen in other asynchronous platforms. It’s fast, easy to read, and easy to write. Perform HTTP requests and other asynchronous operations freely without being concerned about blocking your application and killing your throughput.

×

local lapis = require "lapis" local app = lapis . Application () -- Define a basic pattern that matches / app : match ( "/" , function ( self ) local profile_url = self : url_for ( "profile" , { name = "leafo" }) -- Use inline HTML helper to quickly write a template return self : html ( function () h2 ( "Welcome!" ) text ( "Go to my " ) a ({ href = profile_url }, "profile" ) end ) end ) -- Define a named route pattern with a variable called name app : match ( "profile" , "/:name" , function ( self ) return self : html ( function () div ({ class = "profile" }, "Welcome to the profile of " .. self . params . name ) end ) end ) return app lapis = require " lapis " class extends lapis . Application -- Define a basic pattern that matches / " / " : => profile_url = @url_for " profile " , name: " leafo " -- Use inline HTML helper to quickly write a template @html -> h2 " Welcome! " text " Go to my " a href: profile_url , " profile " -- Define a named route pattern with a variable called name [ profile: " /:name " ] : => @html -> div class: " profile " , -> text " Welcome to the profile of " , @params . name

Models Get a powerful abstraction layer over your database tables just by sub-classing Model :

local Model = require ( "lapis.db.model" ). Model -- Create a model, backed by the table `users` local Users = Model : extend ( "users" ) -- fetch some rows from the table local elderly_users = Users : select ( "where age > ? limit 5" , 10 ) local random_user = Users : find ( 1233 ) -- find by primary key local lee = Users : find ({ name = "Lee" , email = "leemiller@example.com" }) -- create a new row and edit it local user = Users : create ({ name = "Leaf" , email = "leaf@example.com" , age = 6 }) user : update ({ age = 10 }) user : delete () import Model from require " lapis.db.model " -- Create a model, automatically backed by the table `users` class Users extends Model -- fetch some rows from the table elderly_users = Users \ select " where age > ? limit 5 " , 10 random_user = Users \ find 1233 -- find by primary key lee = Users \ find name: " Lee " , email: " leemiller@example.com " -- create a new row and edit it user = Users \ create { name: " Leaf " email: " leaf@example.com " age: 6 } user \ update age: 10 user \ delete !

Templates Write your templates either in etlua or in pure Lua/MoonScript. The template builder syntax works well in MoonScript and lets your organize your templates as classes, allowing you to use inheritance to mix and match methods as you see fit.

<h1 class="header"> <%= "Hello" %> </h1> <% if current_user then %> <div class="user_panel"> Welcome back <%= current_user . name %> </div> <% end %> <div class="body"> Welcome to my site </div> import Widget from require " lapis.html " class Index extends Widget content: => h1 class: " header " , " Hello " @user_panel ! div class: " body " , -> text " Welcome to my site! " user_panel: => return unless @current_user div class: " user_panel " , " Welcome back " .. @current_user . name

Example Using all the provided tools we can quickly and logically construct high performance and low memory web applications. Here’s a more complicated example complete with forms, CSRF protection, and various database queries.

local lapis = require "lapis" local Model = require ( "lapis.db.model" ). Model local capture_errors = require ( "lapis.application" ). capture_errors local csrf = require "lapis.csrf" local Users = Model : extend ( "users" ) local app = lapis . Application () app : before_filter ( function ( self ) self . csrf_token = csrf . generate_token ( self ) end ) app : get ( "list_users" , "/users" , function ( self ) self . users = Users : select () -- `select` all users return { render = true } end ) app : get ( "user" , "/profile/:id" , function ( self ) local user = Users : find ({ id = self . params . id }) if not user then return { status = 404 } end return { render = true } end ) app : post ( "/user/new" , capture_errors ( function ( self ) csrf . assert_token ( self ) Users : create ({ name = self . params . username }) return { redirect_to = self : url_for ( "list_users" ) } end )) app : get ( "new_user" , "/user/new" , function ( self ) return { render = true } end ) return app lapis = require " lapis " import Model from require " lapis.db.model " import respond_to , capture_errors from require " lapis.application " csrf = require " lapis.csrf " class Users extends Model class extends lapis . Application -- Execute code before every action @before_filter => @csrf_token = csrf . generate_token @ [ list_users: " /users " ] : => users = Users \ select ! -- `select` all the users -- Render HTML inline for simplicity @html -> ul -> for user in * users li -> a href: @url_for ( " user " , user . id ) , user . name [ user: " /profile/:id " ] : => user = Users \ find id: @params . id return status: 404 unless user @html -> h2 user . name -- Respond to different HTTP actions to do the right thing [ new_user: " /user/new " ] : respond_to { POST: capture_errors => csrf . assert_token @ Users \ create name: @params . username redirect_to: @url_for " list_users " GET: => @html -> form method: " POST " , action: @url_for ( " new_user " ) , -> input type: " hidden " , name: " csrf_token " , value: @csrf_token input type: " text " , name: " username " }

Where can I learn more? For a guide and tutorial to Lapis, consult the manual. The source of Lapis can be found on Github and issues can be reported on the issues tracker. MoonRocks is an open source application written in Lapis. It is a public Lua Rock repository and the source can be found on GitHub.

Anything else I should know? You can deploy a new Lapis application in a few minutes. If you don’t mind using Heroku then it’s just a matter of using the Lua Buildpack and installing the OpenResty module. You can use most existing Lua libraries with Lapis with no problems. Here are some libraries you might find useful: web_sanitize — HTML sanitization

— HTML sanitization magick — ImageMagick bindings

— ImageMagick bindings cloud_storage — Support for Google Cloud Storage

— Support for Google Cloud Storage lapis-console — Interactive MoonScript console for Lapis that runs inside of your browser

— Interactive MoonScript console for Lapis that runs inside of your browser lapis-exceptions — Exception tracking and reporting