A simple and extensible HTTP server framework for OpenResty, providing a clean method for loading Lua HTTP applications ("resty" modules) into Nginx.
Drawing inspiration from Rack and also Connect, lua-resty-rack allows you to load your application as a piece of middleware, alongside other middleware. Your application can either; ignore the current request, modify the request or response in some way and pass on to other middleware, or take responsibiliy for the request by generating a response.
This library is considered experimental and the API may change without notice. Please feel free to offer suggestions or raise issues here on Github.
Clone the repo and ensure the contents of lib
are in your lua_package_path
in nginx.conf
.
To install middleware for a given location
, you simply call rack.use(middleware)
in the order you wish the modules to run, and then finally call rack.run()
.
server {
location / {
content_by_lua '
local rack = require "rack"
rack.use(require "my.module")
rack.run()
';
}
}
Syntax: rack.use(route?, middleware, options?)
If route
is supplied, the middleware will only be run for requests where route
is in the path (ngx.var.uri
). If the middleware requires any options to be selected they can be provided, usually as a table, as the third parameter.
rack.use('/some/path', app, { foo = 'bar' })
For simple cases, the middleware
parameter can also be a simple function rather than a Lua module. Your function should accept req
, res
, and next
as parameters. See below for instructions on writing middleware.
rack.use(function(req, res, next)
res.header["X-Homer"] = "Doh!"
next()
end)
Syntax: rack.run()
Runs each of the middleware in order, until one chooses to handle the response. Thus, the order in which you call rack.use()
is important.
Middleware applications are simply Lua modules which use the HTTP request and response as a minimal interface. They must implement the function call(options)
which returns a function. The parameters (req, res, next)
are defined below.
-- /lib/method_override.lua
local method_override = {
_VERSION = '0.01',
call = function(options)
return function(req, res, next_middleware)
local key = options['key'] or '_method'
req.method = string.upper(req.args[key] or req.method)
next_middleware()
end
end
}
return method_override
The HTTP method, e.g. GET
, set from ngx.var.request_method
.
The protocol scheme http|https
, set from ngx.var.scheme
.
e.g. /my/uri
, set from ngx.var.uri
.
The hostname, e.g. example.com
, set from ngx.var.host
.
The querystring, e.g. var1=1&var2=2
, set from ngx.var.query_string
.
The query args, as a table
, set from ngx.req.get_uri_args()
.
A table containing the request headers. Keys are matched case insensitvely, and optionally with underscores instead of hyphens. e.g.
req.header["X-Foo"] = "bar"
res.body = req.header.x_foo --> "bar"
An empty string until read with the read_body
middleware.
The HTTP status code to return. There are constants defined for common statuses.
A table of response headers, which can be matched case insensitively and optionally with underscores instead of hyphens (see req.header
above).
The response body.
This parameter is a function provided to the middleware, which may be called to indicate rack should try the next middleware. If your application does not intend to send the response to the browser, it must call this function. If however your application is taking responsibility for the response, simply return without calling next.
Example purely modifying the request.
call = function(options)
return function(req, res, next_middleware)
local key = options['key'] or '_method'
req.method = string.upper(req.args[key] or req.method)
next_middleware()
end
end
Example generating a response.
call = function(options)
return function(req, res)
res.status = 200
res.header['Content-Type'] = "text/plain"
res.body = "Hello World"
end
end
Your application can add new fields or even functions to the req / res tables where appropriate, which could be used by other middleware so long as the dependencies are clear (and one calls use()
in the correct order).
James Hurst <james - AT - pintsized.co.uk> Raimon Grau <raimonster - AT - gmail.com> Enrique García <kikito - AT - gmail.com>
This module is licensed under the 2-clause BSD license.
Copyright (c) 2012, James Hurst [email protected]
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.