REST Lua Service
Introduction
The RestLuaService is a service for initiating Lua scripts running within the LogicApp.
The RestLuaService receives messages from one or more instances of the RestServerApp which is configured to receive REST/HTTP(S) Requests from an external client.
The RestLuaService communicates with the RestServerApp using the REST-S-… messages.
Configuring RestLuaService
The RestLuaService is configured within a LogicApp.
<?xml version="1.0" encoding="utf-8"?>
<n2svcd>
...
<applications>
...
<application name="Logic" module="LogicApp">
<include>
<lib>../apps/logic/lib</lib>
</include>
<parameters>
...
</parameters>
<config>
<services>
<service module="RestServerApp::RestLuaService" libs="../apps/rest_s/lib" script_dir="/var/lib/n2svcd/logic/rest">
<triggers>
...
</triggers>
</service>
</services>
<agents>
...
</agents>
</config>
</application>
...
</application>
...
</n2svcd>
In addition to the Common LogicApp Service Configuration, note the following specific attribute notes, and service-specific attributes.
Under normal installation, the following service
attributes apply:
Parameter Name | Type | XML Type | Description |
---|---|---|---|
module
|
String | Attribute |
[Required] The module name containing the Lua Service code: RestServerApp::RestLuaService
|
libs
|
String | Attribute |
Location of the module for RestLuaService.(Default: ../apps/rest_s/lib )
|
script_dir
|
String | Attribute | [Required] The directory containing scripts used by this service. |
Script Selection (REST Request)
Script selection is optionally configurable using a <triggers>
list in the
service configuration. The service will choose how to handle any request received
by:
- First attempting to match the incoming request against a
<trigger>
definition. Triggers are attempted in the order defined in the<triggers>
list. - Attempting to run a script whoes name is simply the part after the final “/” of the path.
For example, without a matching trigger, an inbound request with path
/APP/rest/echo
will map to a script name of echo
, which will be satisfied
by a file named echo.lua
or echo.lc
in the script_dir
directory configured
for the service.
However, if triggers are defined, for example:
<triggers>
<trigger method="get" path="/APP/rest/echo" script_key="simple_echo"/>
<trigger path_prefix="/APP/rest" script_key="rest_api"/>
</trigger>
Then an inbound GET
request with a path exactly matching /APP/rest/echo
will be handled
by the Lua script in a file called simple_echo.lua
or simple_echo.lc
.
Any other requests where the HTTP path’s prefix is /APP/rest
, regardless of
HTTP method, will be handled by the Lua script rest_api
.
Refer to the LogicApp configuration for more information on directories, library paths, and script caching parameters.
Script Trigger Configuration
The following configuration attributes are required for each <trigger>
defined:
Parameter Name | Type | XML Type | Description |
---|---|---|---|
path_prefix
|
String | Attribute |
[Optional] The string to match against the HTTP path. This path
prefix is used as a substring match against The incoming HTTP request's
path. Any repeated path separators (i.e. instances of //) are converted
into single / before the match is performed.
Only one of |
path
|
String | Attribute |
[Optional] The string to match against the HTTP path. This path
must be a full string match against The incoming HTTP request's path. Any
repeated path separators (i.e. instances of //) are converted into single
/. before comparison.
Only one of |
method
|
String | Attribute | [Optional] The HTTP method (case insensitive) of the HTTP request to match this trigger. Supported method are GET POST PUT PATCH DELETE HEAD and OPTIONS. |
script_key
|
String | Attribute |
[Required] The name of the Lua script (without the .lua
or .lc extension) to execute when a matching inbound request
is received.
|
Note that attributes path_prefix
, path
and method
are all optional. It is valid to define
a trigger with only a script_key
:
For example this triggers configuration:
<triggers>
<trigger script_key="api">
</triggers>
causes all inbound HTTP requests to be handled by the Lua script api.[lc|lua]
Script Global Variables
Scripts run with this service have access to the Common LUA Service Global Variables.
There are no service-specific global variables.
Script Entry Parameters (REST Request)
The Lua script must be a Lua chunk such as the following
example, which includes a single user-level HTTP header named Echo-Flag
:
local n2svcd = require "n2.n2svcd"
local rest = ...
n2svcd.debug ("Echo Supplied REST Inputs:")
n2svcd.debug_var (rest)
return {
content_type = rest.content_type,
content = rest.content,
http_headers = { { name = 'Echo-Flag', value = 'true' } }
}
The chunk will be executed with a single rest
entry parameter which is an object with the
following attributes:
Attribute | Type | Description |
---|---|---|
.remote_ip
|
String | The remote IP address from which the REST HTTP(S) request was sent. |
.remote_port
|
Integer | The remote TCP/IP port from which the REST HTTP(S) request was sent. |
.method
|
String | The HTTP Request method. |
.uri
|
String |
The URI for which the request was received. Includes only path and query. No host/port/auth/user/fragment is present. |
.path
|
String | The URI path. |
.query
|
String | The URI query string (the part following "?" in the URI). |
.query_args
|
String or Object |
If the .query attribute contains & or = then this query_args contains a table of the
name and values, decoded according to common web form conventions. If you wish to have
full control of the decoding, then you should directly reference the undecoded .query .
|
.content_type
|
String | The HTTP Request Content-Type header value. |
.content
|
String | The HTTP Request content. |
.http_headers
|
Array of Object |
The list of HTTP headers parsed from the HTTP Request (see below for object structure). All HTTP headers are present, including Content-Length and Content-Type .If a HTTP header was repeated in the HTTP Request, then it is repeated in this Array. |
Each object in the .http_headers
Array for the rest
entry parameter has the following structure.
Field | Type | Description |
---|---|---|
.name
|
String
|
[Required] The name of the HTTP Request header. |
.value
|
String
|
[Required] The full string value of the HTTP Request header. |
Script Return Parameters (REST Response)
The Lua script is responsible for determing the REST Response which will be sent back in reply to the original REST Request.
The simplest way to do this is by the return value given back to the service at the end of script execution.
For full control over the REST response, the script return value may be a response
object with the following attributes:
Field | Type | Description |
---|---|---|
response
|
Object | Container for the REST response parameters we are to send. |
.code
|
Integer | [Required] The HTTP Response Status Code to send (e.g. 200) |
.content_type
|
String |
The HTTP Response Content-Type header value to send.(Default = Do not return Content-Type header)
|
.content
|
String |
The HTTP Request content to send. (Default = None) |
.http_headers
|
Array of Objects
|
Additional user-level header objects to apply to an outbound HTTP Response (see below for object structure). These headers are added after any headers defined by static RestServerApp application configuration.You should not set the Content-Type or Content-Length headers.(Default = No Additional Headers) |
Each object in the .http_headers
Array for the response
object has the following structure.
Field | Type | Description |
---|---|---|
.name
|
String
|
[Required] The name of the HTTP Response header. |
.value
|
String
|
[Required] The full string value of the HTTP Response header. |
.replace
|
0 / 1
|
If 1 then all previous headers of this name are removed, and this header replaces them.(Default = Append to the existing headers, do not replace) |
Example (returning a Table REST Response):
local n2svcd = require "n2.n2svcd"
local rest = ...
return ({ content_type = "application/json", content = '{ "numrows": 1 }'})
Alternatively, a script may return a simple string instead of a Table.
Example (returning a String REST Response):
local n2svcd = require "n2.n2svcd"
local rest = ...
return "I AM OK YOU ARE OK"
This is a shorthand for code
= 200
, content_type
= text/plain
.
Alternatively, a script may return nil
.
Example (returning a 200 OK with no Content):
local n2svcd = require "n2.n2svcd"
local rest = ...
return nil
This is a shorthand for code
= 200
, no Content, no Content-Type.
The RestLuaService API
The REST Service API can be loaded as follows.
local rest_service_api = require "n2.n2svcd.rest_service"
It is not necessary to load the REST Service API if you are only using the simple response mechanism described above. It is only required if you wish to use any of the extended features described below.
.response
When a Lua Script needs to perform extended processing, it may wish to send an early REST
response before the script completes. This can be done with the response
method on the
REST API.
The response
method takes a single response
parameter. The structure of this
response parameter is identical to the response
parameter which may be returned as
the script return parameter, as described above in
Script Return Parameters (REST Response)
The response
method returns true
.
[Fragment] Example (403 Early Response with text/plain content and cookie):
...
local headers = {}
http.response_headers_set_cookie (headers, "SESSION$", "<none>", { httponly = 1 })
rest_service_api.response ({
code = 403,
content = "ACCESS DENIED!",
content_type = "text/plain",
http_headers = headers
})
...
[post-processing after REST transaction is concluded]
...
[Fragment] Example (200 Early Response with text/plain content):
...
rest_service_api.response ("THANKS FOR CALLING")
...
[post-processing after REST transaction is concluded]