### Handle HTTP Verbs with Lapis respond_to (MoonScript)
Source: https://leafo.net/lapis/reference/quick_reference
Provides an example of handling HTTP GET and POST requests using the `respond_to` decorator within a Lapis application written in MoonScript. It shows common setup logic in `before` and specific actions for GET and POST requests.
```moonscript
lapis = require "lapis"
import respond_to from require "lapis.application"
class App extends lapis.Application
"/login": respond_to {
before:
-- do common setup
if @session.current_user
@write redirect_to: "/"
GET:
-- render the view
render: true
POST:
-- handle the form submission
@session.current_user = try_to_login(@params.username, @params.password)
redirect_to: "/"
}
```
--------------------------------
### Basic Lapis Application Setup (Lua)
Source: https://leafo.net/lapis/index
This snippet demonstrates the fundamental setup of a Lapis web application in Lua. It initializes a Lapis application and defines a simple route that returns 'Hello world!'. This is the starting point for most Lapis applications.
```lua
local lapis = require "lapis"
local app = lapis.Application()
app:match("/", function(self)
return "Hello world!"
end)
return app
```
--------------------------------
### Handle HTTP Verbs with Lapis respond_to (Lua)
Source: https://leafo.net/lapis/reference/quick_reference
Demonstrates using the `respond_to` action decorator in Lapis to define different handlers for HTTP GET and POST requests. It includes a `before` function for common setup and specific handlers for GET (rendering) and POST (login processing).
```lua
local lapis = require("lapis")
local app = lapis.Application()
local respond_to = require("lapis.application").respond_to
app:match("/", respond_to({
-- do common setup
before = function(self)
if self.session.current_user then
self:write({ redirect_to = "/" })
end
end,
-- render the view
GET = function(self)
return { render = true }
end,
-- handle the form submission
POST = function(self)
self.session.current_user =
try_to_login(self.params.username, self.params.password)
return { redirect_to = "/" }
end
}))
```
--------------------------------
### Start Lapis Server
Source: https://leafo.net/lapis/reference/moon_getting_started
Command to start the Lapis development server. Assumes that MoonScript files have been compiled.
```bash
lapis server
```
--------------------------------
### Lua Lapis Configuration Example
Source: https://leafo.net/lapis/reference/lua_creating_configurations
Demonstrates how to define and merge configurations using the `lapis.config` module in Lua. It shows how to set base values and then override them for specific environments like 'production'. The output shows the resulting merged configurations for 'development' and 'production'.
```lua
-- config.lua
local config = require("lapis.config")
config({"development", "production"}, {
host = "example.com",
email_enabled = false,
postgres = {
host = "localhost",
port = "5432",
database = "my_app"
}
})
config("production", {
email_enabled = true,
postgres = {
database = "my_app_prod"
}
})
```
```lua
-- "development"
{
host = "example.com",
email_enabled = false,
postgres = {
host = "localhost",
port = "5432",
database = "my_app",
},
_name = "development"
}
```
```lua
-- "production"
{
host = "example.com",
email_enabled = true,
postgres = {
host = "localhost",
port = "5432",
database = "my_app_prod"
},
_name = "production"
}
```
--------------------------------
### Basic Lapis Application Setup (MoonScript)
Source: https://leafo.net/lapis/index
This snippet shows the equivalent basic setup of a Lapis web application using MoonScript, a language that compiles to Lua. It defines a simple route returning 'Hello world!' in a more concise syntax.
```moonscript
lapis = require "lapis"
class extends lapis.Application
"/": =>
"Hello world!"
```
--------------------------------
### Example cURL command for JSON request
Source: https://leafo.net/lapis/reference/quick_reference
An example of using `curl` to send a JSON-encoded request body to a Lapis application endpoint. It includes setting the `Content-Type` header and providing the JSON data.
```bash
$ curl \
-H "Content-type: application/json" \
-d '{"value": "hello"}' \
'https://localhost:8080/json'
```
--------------------------------
### Accessing Configuration in Lapis (Lua - alternative syntax)
Source: https://leafo.net/lapis/reference/configuration
An alternative syntax for accessing Lapis configuration in Lua. It achieves the same result as the previous example by calling `lapis.config.get()` and accessing the `port` property.
```lua
config = require "lapis.config".get!
print config.port -- shows the current port
```
--------------------------------
### Write HTTP Header
Source: https://leafo.net/lapis/reference/quick_reference
Illustrates two methods for setting HTTP headers in Lapis responses.
```APIDOC
## How do I write a HTTP header?
There are two ways to write headers. In these examples we set the `Access-Control-Allow-Origin` header to `*`
You can return a headers field (or pass it to `write`) from an action:
### Lua Example
```lua
local lapis = require("lapis")
local app = lapis.Application()
app:match("/", function(self)
return {
"OK",
headers = {
["Access-Control-Allow-Origin"] = "*"
}
}
end)
```
### MoonScript Example
```moonscript
lapis = require "lapis"
class App extends lapis.Application
"/": =>
"ok", {
headers: {
"Access-Control-Allow-Origin": "*"
}
}
```
Alternatively, the `res` field of the `self` has a `headers` field that lets you set headers.
### Lua Example
```lua
local lapis = require("lapis")
local app = lapis.Application()
app:match("/", function(self)
self.res.headers["Access-Control-Allow-Origin"] = "*"
return "ok"
end)
```
### MoonScript Example
```moonscript
lapis = require "lapis"
class App extends lapis.Application
"/": =>
@res.headers["Access-Control-Allow-Origin"] = "*"
"ok"
```
If you need to change the content type see below.
```
--------------------------------
### OpenResty Installation Paths Searched by Lapis
Source: https://leafo.net/lapis/reference/getting_started
Lapis searches for the OpenResty Nginx binary in these directories. It prioritizes specific OpenResty installation locations and checks the system's PATH as a fallback. Lapis requires OpenResty, not a standard Nginx installation.
```text
"/usr/local/openresty/nginx/sbin/"
"/usr/local/opt/openresty/bin/"
"/usr/sbin/"
""
```
--------------------------------
### ETLua Template Example
Source: https://leafo.net/lapis/index
An example of an etlua template file demonstrating basic HTML structure, variable interpolation, and conditional logic. Etlua is a templating language for Lapis that allows embedding Lua code.
```etlua
<% if current_user then %>
Welcome back <%= current_user.name %>
<% end %>
Welcome to my site
```
--------------------------------
### Lapis HTTP Module - Basic Usage
Source: https://leafo.net/lapis/reference/utilities
Demonstrates making simple GET and POST requests using the `lapis.http` module, which abstracts the underlying HTTP client.
```APIDOC
## Making HTTP Requests with lapis.http
### Description
The `lapis.http` module provides a unified interface for making HTTP requests, automatically selecting an appropriate client based on the environment (Nginx, Cqueues, or default LuaSocket).
### Methods
- `lapis.http.request(url)`: Performs a GET request.
- `lapis.http.request(options)`: Performs a request with custom options (method, headers, body, etc.).
### Parameters for `lapis.http.request(options)`
#### Request Body (for POST/PUT)
- **url** (string) - The URL to request.
- **method** (string) - The HTTP method (e.g., "POST", "GET"). Defaults to "GET".
- **headers** (table) - A table of request headers.
- **source** (LTN12 stream) - The request body source (for POST/PUT).
- **sink** (LTN12 stream) - The response body sink.
### Request Example (Lua)
```lua
local http = require("lapis.http")
local ltn12 = require("ltn12")
-- Simple GET request
local body, status_code, headers = http.request("http://leafo.net")
-- Simple POST request
local out = {}
local _, status_code, headers = http.request({
url = "http://leafo.net",
method = "POST",
headers = { ["Content-type"] = "application/x-www-form-urlencoded" },
source = ltn12.source.string("param1=value1¶m2=value2"),
sink = ltn12.sink.table(out)
})
local body = table.concat(out)
```
### Request Example (MoonScript)
```moonscript
http = require "lapis.http"
ltn12 = require "ltn12"
-- Simple GET request
body, status_code, headers = http.request "http://leafo.net"
-- Simple POST request
out = {}
_, status_code, headers = http.request {
url: "http://leafo.net",
method: "POST",
headers: { ["Content-type"] = "application/x-www-form-urlencoded" }
source: ltn12.source.string "param1=value1¶m2=value2"
sink: ltn12.sink.table(out)
}
body = table.concat out
```
### Response
- **body** (string) - The response body.
- **status_code** (number) - The HTTP status code.
- **headers** (table) - A table of response headers.
```
--------------------------------
### Database Migrations
Source: https://leafo.net/lapis/reference/database
Guide to managing database schema changes using Lapis migrations.
```APIDOC
## Database Migrations
Lapis provides a module for managing database schema changes (Migrations).
* Running Migrations
* Generating Migration Stubs
* Manually Running Migrations
(Further details on migration commands and usage would be provided here.)
```
--------------------------------
### Basic Lapis Application Structure (Lua)
Source: https://leafo.net/lapis/reference/lua_getting_started
Defines a fundamental Lapis application in Lua. It sets up a GET route for the root path that returns a welcome message including the Lapis version.
```lua
-- app.lua
local lapis = require("lapis")
local app = lapis.Application()
app:get("/", function()
return "Welcome to Lapis " .. require("lapis.version")
end)
return app
```
--------------------------------
### Install Lapis Console with LuaRocks
Source: https://leafo.net/lapis/reference/lapis_console
Installs the Lapis Console package using LuaRocks, the Lua package manager. This command is executed in the terminal.
```bash
$ luarocks install lapis-console
```
--------------------------------
### Read HTTP Header
Source: https://leafo.net/lapis/reference/quick_reference
Demonstrates how to read HTTP headers from an incoming request in Lapis.
```APIDOC
## How do I read a HTTP header?
The `req` field of the `self` passed to actions has a headers fields with all the request headers. They are normalized so you don’t have to be concerned about capitalization.
### Lua Example
```lua
local lapis = require("lapis")
local app = lapis.Application()
app:match("/", function(self)
return self.req.headers["referrer"]
end)
```
### MoonScript Example
```moonscript
lapis = require "lapis"
class App extends lapis.Application
"/": =>
@req.headers["referrer"]
```
```
--------------------------------
### Set Content Type
Source: https://leafo.net/lapis/reference/quick_reference
Explains how to set the `Content-Type` header for responses in Lapis.
```APIDOC
## How do I set the content type?
Either manually set the header as described above, or use the `content_type` option of the `write` method, or action return value:
### Lua Example
```lua
local lapis = require("lapis")
local app = lapis.Application()
app:match("/", function(self)
return { content_type = "text/rss", [[]] }
end)
```
### MoonScript Example
```moonscript
lapis = require "lapis"
class App extends lapis.Application
"/": =>
[[]], content_type: "text/rss"
```
```
--------------------------------
### Lapis Server Startup and Termination Commands
Source: https://leafo.net/lapis/reference/getting_started
Commands for managing the Lapis server. 'lapis server' starts the application by finding and configuring OpenResty. 'lapis term' is used to stop a server that is running in the background by sending a TERM signal to its PID.
```shell
$ lapis server
```
```shell
lapis term
```
--------------------------------
### Database Migrations with Schema Functions (Lua)
Source: https://leafo.net/lapis/reference/database
Provides examples of database migrations in Lua using `lapis.db.schema` functions. It shows how to define migrations as a table of functions, keyed by timestamps, to add columns and create indexes.
```lua
local schema = require("lapis.db.schema")
return {
[1368686109] = function()
schema.add_column("my_table", "hello", schema.types.integer)
end,
[1368686843] = function()
schema.create_index("my_table", "hello")
end
}
```
--------------------------------
### Create Database Tables with Lapis Schema
Source: https://leafo.net/lapis/reference/database
Provides examples of using `lapis.db.schema.create_table` to define and create database tables. It covers specifying columns, data types, and primary keys for both Lua and MoonScript.
```Lua
local schema = require("lapis.db.schema")
local types = schema.types
schema.create_table("users", {
{"id", types.serial},
{"username", types.varchar},
"PRIMARY KEY (id)"
})
```
```MoonScript
schema = require "lapis.db.schema"
import create_table, types from schema
create_table "users", {
{"id", types.serial}
{"username", types.varchar}
"PRIMARY KEY (id)"
}
```
```SQL
CREATE TABLE IF NOT EXISTS "users" (
"id" serial NOT NULL,
"username" character varying(255) NOT NULL,
PRIMARY KEY (id)
);
```
--------------------------------
### HTTP Verb Route Shortcuts
Source: https://leafo.net/lapis/reference/actions
Provides shortcut methods (`get`, `post`, `delete`, etc.) for adding routes specific to HTTP verbs, utilizing the `match` method internally.
```APIDOC
## HTTP Verb Route Shortcuts
### Description
These are shortcut methods for `application:match` that specifically handle requests for a given HTTP verb. They use `respond_to` internally to match the verb.
### Methods
- `application:get(...)`
- `application:post(...)`
- `application:delete(...)`
- (And other HTTP verbs)
### Endpoint
N/A (These are methods for defining routes within the application)
### Parameters
Same arguments as `application:match`.
### Request Example
```lua
-- Lua MoonScript
app:get("/users", function(self) return User.all() end)
app:post("/users", function(self) return User.create(self.params) end)
```
```moonscript
-- MoonScript
app:get "/users", => User.all()
app:post "/users", => User.create(@params)
```
### Response
N/A (These methods configure routes; the response is determined by the action function executed when the route is matched.)
```
--------------------------------
### Create New Lapis Project
Source: https://leafo.net/lapis/reference/command_line
Initializes a new Lapis project with starter files. Supports generating configurations for Nginx or cqueues, and templates in Lua or MoonScript. Optionally includes .gitignore, Tupfile, and rockspec files. Use --force to bypass environment checks.
```bash
Usage: lapis new ([--nginx] | [--cqueues]) ([--lua] | [--moonscript])
[-h] [--etlua-config] [--git] [--tup] [--rockspec] [--force]
Create a new Lapis project in the current directory
Options:
-h, --help Show this help message and exit.
--nginx Generate config for nginx server (default)
--cqueues Generate config for cqueues server
--lua Generate app template file in Lua (default)
--moonscript, --moon Generate app template file in MoonScript
--etlua-config Use etlua for templated configuration files (eg. nginx.conf)
--git Generate default .gitignore file
--tup Generate default Tupfile
--rockspec Generate a rockspec file for managing dependencies
--force Bypass errors when detecting functional server environment
```
--------------------------------
### Basic Route and Action in MoonScript
Source: https://leafo.net/lapis/reference/moon_getting_started
A simple Lapis application demonstrating a route '/hello' mapped to an action that returns 'Hello World!'. It illustrates the basic structure of a route and its corresponding action function.
```moonscript
lapis = require "lapis"
class App extends lapis.Application
"/hello": => "Hello World!"
```
--------------------------------
### Complex has_many relation with custom options
Source: https://leafo.net/lapis/reference/models
Provides an example of a more complex 'has_many' relation setup. It utilizes custom 'where', 'order', and 'key' options to define the relationship and fetching behavior for 'authored_posts'.
```lua
local Model = require("lapis.db.model").Model
local Users = Model:extend("users", {
relations = {
{"authored_posts",
has_many = "Posts",
where = {deleted = false},
order = "id desc",
key = "poster_id"}
}
})
```
```moonscript
import Model from require "lapis.db.model"
class Users extends Model
@relations:
{"authored_posts"
has_many: "Posts"
where: {deleted = false}
order: "id desc"
key: "poster_id"}
```
```lua
local posts = user:get_authored_posts()
```
```moonscript
posts = user\get_authored_posts!
```
```sql
SELECT * from "posts" where "poster_id" = 123 and deleted = FALSE order by id desc
```
--------------------------------
### Nginx Configuration Interpolation Example
Source: https://leafo.net/lapis/reference/configuration
This snippet demonstrates how Lapis configuration values can be interpolated into an Nginx configuration file. The `${{VARIABLE_NAME}}` syntax is used for variable substitution, often sourced from environment variables.
```nginx
events {
worker_connections ${{WORKER_CONNECTIONS}};
}
```
--------------------------------
### Establishing A Connection
Source: https://leafo.net/lapis/reference/database
Details on how to establish database connections for PostgreSQL, MySQL, and SQLite.
```APIDOC
## Establishing A Connection
Lapis supports connections to PostgreSQL, MySQL, and SQLite. The specific library used depends on the environment and configuration.
### PostgreSQL
* Uses `pgmoon`. Supports OpenResty’s cosocket API, LuaSocket, and cqueues.
### MySQL
* In OpenResty environments: `lua-resty-mysql`.
* Otherwise: `LuaSQL-MySQL`.
### SQLite
* Uses `LuaSQLite3`.
* Note: SQLite queries are blocking and do not use connection pooling as it's embedded into the application.
```
--------------------------------
### Set Content Type in Lapis (MoonScript)
Source: https://leafo.net/lapis/reference/quick_reference
Demonstrates setting the response `content_type` in Lapis using MoonScript. The example shows utilizing the `content_type` option directly in the action's return value for efficiency.
```moonscript
lapis = require "lapis"
class App extends lapis.Application
"/": =>
[[]], content_type: "text/rss"
```
--------------------------------
### Get Model Table Name (Lua, MoonScript)
Source: https://leafo.net/lapis/reference/models
The `table_name()` method returns the name of the database table associated with the model. This method can be overridden in a model class to specify a custom table name. Examples are shown for both Lua and MoonScript syntax.
```lua
Model:extend("users"):table_name() --> "users"
Model:extend("user_posts"):table_name() --> "user_posts"
class Users extends Model
@table_name: => "active_users"
```
```moonscript
(class Users extends Model)\table_name! --> "users"
(class UserPosts extends Model)\table_name! --> "user_posts"
(class Users extends Model)
@table_name: => "active_users"
```
--------------------------------
### Create a New Lapis Project with MoonScript
Source: https://leafo.net/lapis/reference/moon_getting_started
Command to initialize a new Lapis project with MoonScript support. It generates a default Nginx configuration and a skeleton MoonScript application file.
```bash
$ lapis new --moonscript
```
--------------------------------
### Render JSON Response in Lapis (Lua)
Source: https://leafo.net/lapis/reference/quick_reference
Provides a Lua example for rendering a JSON response in Lapis. It utilizes the `json` option within the action's return value to automatically serialize a Lua table into a JSON string.
```lua
local lapis = require("lapis")
local app = lapis.Application()
app:match("/", function(self)
return {
json = {
success = true,
message = "hello world"
}
}
end)
```
--------------------------------
### Basic Lapis Application Structure in MoonScript
Source: https://leafo.net/lapis/reference/moon_getting_started
A minimal Lapis application written in MoonScript. It defines a single route '/' that responds with a welcome message including the Lapis version.
```moonscript
lapis = require "lapis"
class extends lapis.Application
"/": =>
"Welcome to Lapis #{require "lapis.version"}!"
```
--------------------------------
### Generate New Lapis Project
Source: https://leafo.net/lapis/reference/lua_getting_started
Command to create a new Lapis project skeleton. Assumes OpenResty and Nginx configurations are pre-existing. Initializes an 'app.lua' file for the application.
```bash
$ lapis new
```
--------------------------------
### Overriding Configuration with Environment Variables
Source: https://leafo.net/lapis/reference/configuration
This example shows how to override Lapis configuration values using environment variables. By prefixing the configuration name with 'LAPIS_' and making it uppercase, the environment variable takes precedence. Note that values are read as strings and may require type coercion.
```bash
$ LAPIS_WORKER_CONNECTIONS=5 lapis server
```
--------------------------------
### Get Model Singular Name (Lua, MoonScript)
Source: https://leafo.net/lapis/reference/models
The `singular_name()` method returns the singular form of the model's name, typically derived from the table name. This is used internally by Lapis for features like `include_in` and determining foreign key names in relations (`has_one`, `has_many`). Examples are provided for Lua and MoonScript.
```lua
Model:extend("users"):singular_name() --> "user"
Model:extend("user_posts"):singular_name() --> "user_post"
```
```moonscript
(class Users extends Model)\singular_name! --> "user"
(class UserPosts extends Model)\singular_name! --> "user_post"
```
--------------------------------
### Handling HTTP Verbs with respond_to
Source: https://leafo.net/lapis/reference/actions
Demonstrates how to handle different HTTP verbs (like GET and POST) within a single route using the `respond_to` helper. It also shows how to define a `before` filter.
```APIDOC
## Handling HTTP Verbs with `respond_to`
### Description
The `respond_to` helper allows a single route handler to respond differently based on the incoming HTTP verb. It accepts a table where keys are HTTP verbs and values are the corresponding handler functions. A `before` filter can also be specified to run before any verb-specific handler.
### Method
`respond_to(options)` where `options` is a table containing HTTP verb keys (e.g., `GET`, `POST`) and their associated functions, and an optional `before` function.
### Endpoint Examples
- `/create-account`
- `/edit-user/:id`
### Parameters
- **HTTP Verb** (e.g., `GET`, `POST`) - A function to execute for the specified HTTP verb.
- **before** (function, optional) - A function to execute before the verb-specific handler. If this function calls `self:write()`, subsequent handlers will not be executed.
### Request Example (Lua MoonScript)
```moonscript
app:match("create_account", "/create-account", respond_to({
GET = function(self)
return { render = true }
end,
POST = function(self)
do_something(self.params)
return { redirect_to = self:url_for("index") }
end
}))
app:match("edit_user", "/edit-user/:id", respond_to({
before = function(self)
self.user = Users:find(self.params.id)
if not self.user then
self:write({"Not Found", status = 404})
end
end,
GET = function(self)
return "Edit account " .. self.user.name
end,
POST = function(self)
self.user:update(self.params.user)
return { redirect_to = self:url_for("index") }
end
}))
```
### Request Body
- When `Content-Type` is `application/x-www-form-urlencoded` on `POST` requests, parameters are parsed into `self.params`.
### Response Example (Success)
- Depends on the handler function; can return rendered content, redirects, or other Lapis responses.
### Error Handling
- If the `before` filter calls `self:write({..., status = 404})`, a 404 Not Found response is returned.
```
--------------------------------
### lapis new
Source: https://leafo.net/lapis/reference/command_line
Creates a new Lapis project in the current directory. It generates starter files for configuration and application logic. Options allow customization of server type (Nginx or Cqueues), language (Lua or MoonScript), and additional files like .gitignore, Tupfile, and rockspec.
```APIDOC
## `lapis new`
### Description
Creates a new Lapis project in the current directory by generating starter files. This command can be helpful for getting started quickly, but it's not mandatory to use it.
### Method
CLI Command
### Endpoint
N/A (CLI Command)
### Parameters
#### CLI Arguments
- **`[--nginx | --cqueues]`**: Server type. `--nginx` for Nginx (default), `--cqueues` for Cqueues.
- **`[--lua | --moonscript]`**: Language for app template. `--lua` (default), `--moonscript` for MoonScript.
#### Options
- **`-h, --help`**: Show help message and exit.
- **`--etlua-config`**: Use etlua for templated configuration files.
- **`--git`**: Generate a default `.gitignore` file.
- **`--tup`**: Generate a default `Tupfile`.
- **`--rockspec`**: Generate a rockspec file for dependency management.
- **`--force`**: Bypass errors when detecting a functional server environment.
### Request Example
```bash
lapis new --moonscript --rockspec
```
### Response
#### Success Response
Generates project files in the current directory.
#### Response Example
```
(Project files created: nginx.conf, mime.types, app.lua, config.lua, etc.)
```
```
--------------------------------
### Lapis Request Write Method Example
Source: https://leafo.net/lapis/reference/actions
Illustrates the usage of the `request:write()` method in Lapis. It shows how strings, callable functions, and tables are handled when appended to the output buffer or options table.
```lapis
request:write(string_argument)
request:write(function_argument)
request:write(table_argument)
```
--------------------------------
### Example JSON Error Response from Lapis
Source: https://leafo.net/lapis/reference/exception_handling
This is an example of the JSON output generated by `capture_errors_json` when an error occurs. The response includes an `errors` key containing an array of error messages.
```json
{ errors: ["something bad happened"] }
```
--------------------------------
### Set Up User Session with Before Filter (Lua)
Source: https://leafo.net/lapis/reference/actions
This example shows how to set up a user session before each action is processed. It checks for a user in the session and loads the user object if found. This filter runs before the root path '/' action.
```lua
local app = lapis.Application()
app:before_filter(function(self)
if self.session.user then
self.current_user = load_user(self.session.user)
end
end)
app:match("/", function(self)
return "current user is: " .. tostring(self.current_user)
end)
```
```moonscript
lapis = require "lapis"
class App extends lapis.Application
@before_filter =>
if @session.user
@current_user = load_user @session.user
"/": =>
"current user is: #{@current_user}"
```
--------------------------------
### Lapis Application with Database and CSRF (Lua)
Source: https://leafo.net/lapis/index
A comprehensive Lapis application example written in pure Lua. It demonstrates setting up routes for listing users, viewing a user profile, and creating a new user with CSRF protection and database interactions using Lapis models.
```lua
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("new_user", "/user/new", capture_errors(function(self)
csrf.assert_token(self)
Users:create({
name = assert_error(self.params.username, "Missing username")
})
return { redirect_to = self:url_for("list_users") }
end))
app:get("new_user", "/user/new", function(self)
return { render = true }
end)
return app
```
--------------------------------
### Install Tableshape Validation Library
Source: https://leafo.net/lapis/reference/input_validation
This command installs the Tableshape library, which is required for using Lapis's new validation system. Tableshape provides powerful tools for validating and transforming data structures.
```bash
$ luarocks install tableshape
```
--------------------------------
### Define Polymorphic Belongs To Relation (MoonScript)
Source: https://leafo.net/lapis/reference/models
Example of defining a polymorphic_belongs_to relation in Lapis ORM using MoonScript. This demonstrates the equivalent syntax to the Lua example for creating a relation where a model can belong to multiple other types.
```moonscript
import Model from require "lapis.db.model"
class Posts extends Model
@relations: {
{"object", polymorphic_belongs_to: {
[1]: "VideoGames"
[2]: "Books"
}}
}
```
--------------------------------
### Convenience HTTP Verb Wrappers
Source: https://leafo.net/lapis/reference/actions
Introduces the convenience methods like `app:get()`, `app:post()`, `app:delete()`, and `app:put()` as shortcuts for defining actions that handle specific HTTP verbs.
```APIDOC
## Convenience HTTP Verb Wrappers
### Description
Lapis provides shortcut methods for the most common HTTP verbs (`get`, `post`, `delete`, `put`) that act as wrappers around `respond_to`. These simplify the definition of routes that only need to handle a single HTTP verb.
### Method
- `app:get(pattern, handler)`
- `app:post(pattern, handler)`
- `app:delete(pattern, handler)`
- `app:put(pattern, handler)`
### Endpoint Examples
- `/test` (for GET requests)
- `/delete-account` (for DELETE requests)
### Parameters
- **pattern** (string) - The URL pattern for the route.
- **handler** (function) - The function to execute when a request with the corresponding HTTP verb matches the pattern.
### Request Example (Lua)
```lua
app:get("/test", function(self)
return "I only render for GET requests"
end)
app:delete("/delete-account", function(self)
-- do something destructive
end)
```
### Response Example (Success)
- Returns the value returned by the handler function.
```
--------------------------------
### Lapis HTTP GET and POST Requests (MoonScript)
Source: https://leafo.net/lapis/reference/utilities
Illustrates making GET and POST HTTP requests with `lapis.http` in MoonScript. This version uses MoonScript's syntax for defining tables and function calls. Requires `lapis.http` and `ltn12`.
```moonscript
http = require "lapis.http"
ltn12 = require "ltn12"
-- a simple GET request
body, status_code, headers = http.request "http://leafo.net"
out = {}
_, status_code, headers = http.request {
url: "http://leafo.net",
method: "POST",
headers: { ["Content-type"] = "application/x-www-form-urlencoded" }
source: ltn12.source.string "param1=value1¶m2=value2"
sink ltn12.sink.table(out)
}
body = table.concat out
```
--------------------------------
### Lapis Application with Multiple Routes in MoonScript
Source: https://leafo.net/lapis/reference/moon_getting_started
An example of a Lapis application in MoonScript with three routes: a homepage, a list of favorite foods, and a detail page for each food. It demonstrates inline HTML generation and URL for route generation.
```moonscript
lapis = require "lapis"
favorite_foods = {
"pizza": "Wow pizza is the best! Definitely my favorite"
"egg": "A classic breakfast, never leave home without"
"ice cream": "Can't have a food list without a dessert"
}
class App extends lapis.Application
[index: "/"]: =>
-- Render HTML inline for simplicity
@html ->
h1 "My homepage"
a href: @url_for("list_foods"), "Check out my favorite foods"
[list_foods: "/foods"]:
@html ->
ul ->
for food in pairs favorite_foods
li ->
a href: @url_for("food", name: food), food
[food: "/food/:name"]:
food_description = favorite_foods[@params.name]
unless food_description
return "Not found", status: 404
@html ->
h1 @params.name
h2 "My thoughts on this food"
p food_description
```
--------------------------------
### Lapis HTTP GET and POST Requests (Lua)
Source: https://leafo.net/lapis/reference/utilities
Demonstrates how to perform simple GET and POST HTTP requests using the `lapis.http` module in Lua. It utilizes LTN12 for handling request bodies and sinks. Requires `lapis.http` and `ltn12`.
```lua
local http = require("lapis.http")
local ltn12 = require("ltn12")
-- a simple GET request
local body, status_code, headers = http.request("http://leafo.net")
-- a simple POST request
local out = {}
local _, status_code, headers = http.request({
url = "http://leafo.net",
method = "POST",
headers = { ["Content-type"] = "application/x-www-form-urlencoded" },
source = ltn12.source.string("param1=value1¶m2=value2"),
sink = ltn12.sink.table(out)
})
local body = table.concat(out)
```
--------------------------------
### MoonScript Configuration Builder Example
Source: https://leafo.net/lapis/reference/moon_creating_configurations
Demonstrates the MoonScript configuration builder syntax using function calls to define variables and structure configurations. It includes conditional logic, nested table definitions, merging behavior for duplicate keys, and inclusion of external functions. The output shows the generated Lua table.
```moonscript
some_function = -> steak "medium_well"
config "development", ->
hello "world"
if 20 > 4
color "blue"
else
color "green"
custom_settings ->
age 10
enabled true
-- tables are merged
extra ->
name "leaf"
mood "happy"
extra ->
name "beef"
shoe_size 12
include some_function
include some_function
-- a normal table can be passed instead of a function
some_list {
1,2,3,4
}
-- use set to assign names that are unavailable
set "include", "hello"
```
```lua
{
hello: "world"
color: "blue"
custom_settings: {
age: 10
enabled: true
}
extra: {
name: "beef"
mood: "happy"
shoe_size: 12
steak: "medium_well"
}
steak: "medium_well"
some_list: { 1,2,3,4 }
include: "hello"
}
```
--------------------------------
### Optional Validation Example
Source: https://leafo.net/lapis/reference/input_validation
Demonstrates how to use optional validations in Lapis. The 'optional = true' flag allows a validation to be skipped if the parameter's value is nil. This example validates a 'color' parameter, ensuring it exists and meets length constraints only if provided.
```moonscript
validate.assert_valid(self.params, {
{ "color", exists = true, min_length = 2, max_length = 25, optional = true },
})
```
```moonscript
assert_valid @params,
{
{ "color", exists: true, min_length: 2, max_length: 25, optional: true },
}
```
--------------------------------
### Basic etlua Tags and Usage in Lapis
Source: https://leafo.net/lapis/reference/lua_getting_started
Demonstrates the fundamental etlua tags for embedding Lua code and expressions within HTML. Includes an example of assigning data in a Lapis application action and rendering it in an etlua view, showing verbatim code execution and HTML-escaped output.
```lua
-- 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
```
```html
Here are my favorite things
<% for i, thing in pairs(my_favorite_things) do %>
- <%= thing %>
<% end %>
```
--------------------------------
### Curl Request Example for JSON Parameters
Source: https://leafo.net/lapis/reference/utilities
This example demonstrates how to send a JSON payload to a Lapis application endpoint configured to use `json_params`. It uses `curl` to send a POST request with the `Content-type` header set to `application/json` and a JSON string in the request body.
```shell
$ curl \
-H "Content-type: application/json" \
-d '{"value": "hello"}' \
'https://localhost:8080/json'
```
--------------------------------
### Define a simple '/hello' route in Lapis
Source: https://leafo.net/lapis/reference/actions
This snippet demonstrates how to define a basic route that responds with a JSON object. It shows the implementation in both Lua and MoonScript, highlighting their distinct syntax for defining routes and JSON responses.
```lua
app:match("/hello", function(self)
return { json = { hello = "world" } }
end)
```
```moonscript
class App extends lapis.Application
"/hello": =>
json: { hello: "world!" }
```
--------------------------------
### Application Methods for Routing
Source: https://leafo.net/lapis/reference/actions
Provides an overview of the methods available on the `lapis.Application` object for defining routes and actions.
```APIDOC
## Application Methods for Routing
These methods are used to define routes and associate them with action functions or module names.
### `application:match([route_name], route_patch, action_fn)`
- **Purpose**: Defines a route that matches a given `route_patch` and executes the `action_fn`.
- **Parameters**:
- `route_name` (string, optional): A name for the route, used for URL generation.
- `route_patch` (string): The URL path pattern to match.
- `action_fn` (function or string): The function to execute or the module name to load the action from.
### `application:get(route_patch, action_fn)`
- **Purpose**: Defines a route that specifically handles GET requests.
### `application:post(route_patch, action_fn)`
- **Purpose**: Defines a route that specifically handles POST requests.
### `application:delete(route_patch, action_fn)`
- **Purpose**: Defines a route that specifically handles DELETE requests.
### `application:put(route_patch, action_fn)`
- **Purpose**: Defines a route that specifically handles PUT requests.
```
--------------------------------
### POST /user/:id
Source: https://leafo.net/lapis/reference/input_validation
Example of using `with_params` to validate and extract parameters for a user action.
```APIDOC
## POST /user/:id
### Description
This endpoint uses `with_params` to validate the `id` and `action` parameters from the request. If validation succeeds, it proceeds to execute the action function, passing the validated parameters.
### Method
POST
### Endpoint
/user/:id
### Parameters
#### Path Parameters
- **id** (db_id) - Required - The ID of the user.
#### Query Parameters
None
#### Request Body
None (parameters are expected to be validated from path and potentially other sources like query or form data, depending on Lapis configuration).
### Request Example
```json
{
"action": "update"
}
```
### Response
#### Success Response (200)
- **Output**: The result of the executed action function. In the example, it prints to the server console.
#### Response Example
```
Perform update on user 123
```
#### Error Response (e.g., 400)
- **error** (string) - A JSON object detailing the validation errors if the parameters do not match the expected schema.
```
--------------------------------
### lapis server
Source: https://leafo.net/lapis/reference/command_line
Starts the configured web server for the Lapis application in a specified environment. It reads the configuration to determine the server type and then launches the application. Supports OpenResty and Cqueues servers, with options for specifying the OpenResty binary path.
```APIDOC
## `lapis server`
### Description
Starts the configured webserver for your Lapis application under the specified environment. It reads the configuration file to determine the server type and then attempts to start the application.
### Method
CLI Command
### Endpoint
N/A (CLI Command)
### Parameters
#### Arguments
- **`[environment]`**: The environment to run the server in (e.g., `development`, `production`).
#### Environment Variables
- **`LAPIS_OPENRESTY`**: Manually specify the path to the OpenResty binary if it's not found in standard locations.
### Request Example
```bash
lapis server development
LAPIS_OPENRESTY=/usr/local/openresty/nginx/sbin/nginx lapis server production
```
### Response
#### Success Response
Starts the web server and listens for requests.
#### Response Example
```
(Server started successfully. Listening on port X...)
```
```
--------------------------------
### Complex `has_many` Example
Source: https://leafo.net/lapis/reference/models
Demonstrates a more complex `has_many` relation configuration with custom keys, filtering, and ordering.
```APIDOC
## Complex `has_many` Example
Here’s a more complex example utilizing some of the options for `has_many`:
### Lua Example
```lua
local Model = require("lapis.db.model").Model
local Users = Model:extend("users", {
relations = {
{"authored_posts",
has_many = "Posts",
where = {deleted = false},
order = "id desc",
key = "poster_id"}
}
})
```
### MoonScript Example
```moonscript
import Model from require "lapis.db.model"
class Users extends Model
@relations:
{"authored_posts"
has_many: "Posts"
where: {deleted = false}
order: "id desc"
key: "poster_id"}
```
### Fetching Related Objects
#### Lua Example
```lua
local posts = user:get_authored_posts()
```
#### MoonScript Example
```moonscript
posts = user\get_authored_posts!
```
#### SQL Example
```sql
SELECT * from "posts" where "poster_id" = 123 and deleted = FALSE order by id desc
```
```
--------------------------------
### Configure 'test' Environment Database (MoonScript)
Source: https://leafo.net/lapis/reference/testing
This MoonScript snippet shows the equivalent configuration for the 'test' environment's PostgreSQL database as the Lua example. It uses MoonScript syntax to define the database settings for testing. Add this to your 'config.moon' file.
```moonscript
config = require "lapis.config"
-- other configuration ...
config "test", ->
postgres {
backend: "pgmoon"
database: "myapp_test"
}
```
--------------------------------
### Lapis Routing and HTML Generation (MoonScript)
Source: https://leafo.net/lapis/index
This MoonScript snippet demonstrates advanced Lapis routing, mirroring the Lua example. It shows named routes with parameters and the use of HTML builder syntax for generating markup, defining a root and a profile route.
```moonscript
lapis = require "lapis"
class extends lapis.Application
-- Define a basic pattern that matches /
"/": =>
profile_url = @url_for "profile", name: "leafo"
-- Use HTML builder syntax helper to quickly and safely write markup
@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
```
--------------------------------
### Render JSON Response
Source: https://leafo.net/lapis/reference/quick_reference
Details how to send JSON data as an HTTP response using Lapis.
```APIDOC
## How to do I render JSON?
Use the `json` option of the `write` method, or the action’s return value:
### Lua Example
```lua
local lapis = require("lapis")
local app = lapis.Application()
app:match("/", function(self)
return {
json = {
success = true,
message = "hello world"
}
}
end)
```
### MoonScript Example
```moonscript
lapis = require "lapis"
class App extends lapis.Application
"/": =>
{
json: {
success: true
message: "hello world"
}
}
```
```
--------------------------------
### Handle HTTP Verbs with Lapis respond_to (Lua & MoonScript)
Source: https://leafo.net/lapis/reference/actions
Shows how to use the `respond_to` helper to define different actions for GET and POST requests on the same route. Includes basic rendering and redirection logic. Supports Lua and MoonScript.
```lua
local lapis = require("lapis")
local respond_to = require("lapis.application").respond_to
local app = lapis.Application()
app:match("create_account", "/create-account", respond_to({
GET = function(self)
return { render = true }
end,
POST = function(self)
do_something(self.params)
return { redirect_to = self:url_for("index") }
end
}))
```
```moonscript
lapis = require "lapis"
import respond_to from require "lapis.application"
class App extends lapis.Application
[create_account: "/create-account"]: respond_to {
GET: => render: true
POST: =>
do_something @params
redirect_to: @url_for "index"
}
```
--------------------------------
### Run Lapis Server
Source: https://leafo.net/lapis/reference/command_line
Starts the Lapis web server for a specified environment. It configures and launches either an OpenResty server or a cqueues-based server. The OpenResty server path can be specified using the LAPIS_OPENRESTY environment variable.
```bash
$ lapis server [environment]
```
```bash
LAPIS_OPENRESTY=/home/leafo/bin/openresty lapis server
```
```bash
$ nginx -p "$(pwd)" -c "nginx.conf.compiled"
```