lua_getting_started.md
title: Creating a Lapis Application with Lua⌗
Creating a Lapis Application with Lua⌗
Generating a New Project⌗
If you haven’t already, read through the generic getting started guide for
information on creating a new project skeleton along with details on OpenResty,
Nginx configurations, and the lapis
command.
You can start a new Lua project in the current directory by running the following command:
$ lapis new --lua
The default nginx.conf
reads a file called app.lua
for your application. A
basic one is provided with the lapis new
command.
app.lua
is a regular Lua module that contains the application. You can even
require the module like any other in the regular Lua interpreter. It looks like
this:
-- app.lua
local lapis = require("lapis")
local app = lapis.Application()
app:get("/", function()
return "Welcome to Lapis " .. require("lapis.version")
end)
return app
Try it out by starting the server:
lapis server
Visit http://localhost:8080 to see the page.
To change the port we can create a configuration. Create config.lua
.
In this example we change the port in the development
environment to 9090:
-- config.lua
local config = require("lapis.config")
config("development", {
port = 9090
})
You can read more about configurations on the Configurations and Environments guide.
The development
environment is used and loaded automatically when lapis server
is run with no additional arguments. (And the file
lapis_environment.lua
doesn’t exist)
Lapis uses a handful of fields in the configuration (such as port
), other
fields can be used to store anything you want. For example:
-- config.lua
local config = require("lapis.config")
config("development", {
greeting = "Hello world"
})
You can get the current configuration by calling get
. It returns a plain Lua
table:
-- app.lua
local lapis = require("lapis")
local config = require("lapis.config").get()
local app = lapis.Application()
app:get("/", function(self)
return config.greeting .. " from port " .. config.port
end)
return app
Creating a View⌗
Now that we can create basic pages we’ll likely want to render something a bit more complex. Lapis comes with support for etlua, an Lua templating language that lets you insert Lua mixed in with text and HTML.
A view is a file that is responsible for generating the HTML. Typically your action will prepare all the data for your view and then tell it to render.
By default Lapis searches for views in views/
directory. Lets create a new
view there, index.etlua
. We won’t use any of etlua’s special markup just yet,
so it will look like a normal HTML file.
<!-- views/index.etlua -->
<h1>Hello world</h1>
<p>Welcome to my page</p>
You’ll notice that <html>
, <head>
, and <body>
tags aren’t there. The view
typically renders the inside of the page, and the layout is responsible for
what goes around it. We’ll look at layouts further down.
Now lets create the application which renders our view:
-- app.lua
local lapis = require("lapis")
local app = lapis.Application()
app:enable("etlua")
app:get("/", function(self)
return { render = "index" }
end)
return app
etlua
is not enabled by default, you must enable it by calling the enable
method on your application instance.
We use the render
parameter of our action’s return value to instruct what
template to use when rendering the page. In this case "index"
refers to the
module with the name views.index
. etalua
injects itself into Lua’s
require
method and so when the module views.index
is loaded, an attempt to
read and parse the file views/index.etlua
is made.
Running the server and navigating to it in the browser should show our rendered template.
Working with etlua
⌗
etlua
comes with the following tags for injecting Lua into your templates:
<% lua_code %>
runs Lua code verbatim<%= lua_expression %>
writes result of expression to output, HTML escaped<%- lua_expression %>
same as above but with no HTML escaping
Learn more about the etlua integration in the etlua guide.
In the following example we assign some data in the action, then print it out in our view:
-- app.lua
local lapis = require("lapis")
local app = lapis.Application()
app:enable("etlua")
app:get("/", function(self)
self.my_favorite_things = {
"Cats",
"Horses",
"Skateboards"
}
return { render = "list" }
end)
return app
<!-- views/list.etlua -->
<h1>Here are my favorite things</h1>
<ol>
<% for i, thing in pairs(my_favorite_things) do %>
<li><%= thing %></li>
<% end %>
</ol>
Creating a Layout⌗
A layout is a separate shared template that wraps the content of every page. Lapis comes with a basic layout to get you started but you’ll most likely want to replace it with something custom.
We’ll write the layout in etlua just like our views. Create views/layout.etlua
:
<!-- views/layout.etlua -->
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="UTF-8">
<title><%= page_title or "My Page" %></title>
</head>
<body>
<h1>Greetings</h1>
<% content_for("inner") %>
</body>
</html>
The content_for
function is a special function built into templates that
allows you to send data from a view to a layout. Lapis puts the rendered result
of the view into the content variable named inner
. You’ll note that we don’t
need to use any of the etlua tags that write into the page. This is because
content_for
efficiently puts its result directly into the output buffer.
Any other variables and helper functions that would normally be available in a view are also available in the layout.
Now that the layout is written it can be assigned to the application:
local app = lapis.Application()
app:enable("etlua")
app.layout = require "views.layout"
-- the rest of the application...
The syntax is slightly different than rendering a view. Instead of assigning a
template name to the layout
field, we assign the actual template object. This
can be obtained by just requiring it by the module name: "views.layout"
. As
described above, etlua takes care of converting the .etlua
file into something
usable by Lua.