Advanced Endpoints
Advanced Endpoints is a very powerful way to embed your corporate logic directly in the Web API. This eliminates the need of the middleware between inmation and ERP or other business applications. For instance, Web API can directly react on ERP HTTP requests and respond in a format, which is most suitable for the caller.
-
Allows advanced endpoint implementation.
-
Behave as a native endpoints.
-
Is able to route any URL.
-
Supports many HTTP methods.
-
Accepts various types of arguments
-
Response can be 'any' text based format
Description
The advanced endpoint embeds custom endpoints by hosting Lua libraries in the system. The name of the Lua library will be the first part of the custom path, the second part of the custom path will be the function name, unless the library returns a function itself. For example: api/v2/execfunction/corporate/readMachineHistory. In this example is corporate the name of the Lua library and readMachineHistory is a name of the function, which will be executed to process the request.
The implementation of the Advanced Endpoint is done in Lua. The Lua script will be stored as a Script Library on the Web API object in the Server Model as a Script Library). Such a library can be implemented in two distinctive ways:
-
Returning an object (Lua table) containing function(s).
-
Returning one function.
The signature of the function is always the same. Containing three arguments: (arg, req, hlp).
-
(
arg
) argument
The content of the arg parameter depends on what is passed in the body of the HTTP request and will be set as follows:-
Empty Body: If the request body is not set or empty, arg will be initialised to an empty Lua table.
-
The body is a JSON object - More specifically, the request payload is of type JSON and the root element is not an array. For example:
{ "start_time": "2019-04-02T10:00:00.000Z", "limit": 35 }
In this case, the
arg
parameter will be set to a Lua table which looks like this:{ ["start_time"] = "2019-04-02T10:00:00.000Z", ["limit"] = 35 }
In other words, the arg Lua table will be a dictionary with a key-value-pair for each property in the JSON object. The values of the properties will be converted to Lua string, numbers or tables as appropriate.
-
All other non-empty request bodies: If the request content type is not JSON or it is a JSON array (as opposed to a JSON object), then arg will be a Lua table with a single key called data and value set to the request body. Let’s look at a couple of examples:
-
Text Request body: Let’s say the body was set to “Hello World”, in this case arg will look like this:
{ data = "Hello World" }
-
JSON Array body: Body contains a simple array, say [1, 2, 3, 4]. In this case the arg parameter will be set to:
{ data = { 1, 2, 3, 4 } }
-
Array of Objects body: Body contains an array of objects: [ { “temp”:25.2}, {“temp”:27.1} ]. Then we get a Lua table that looks like this:
{ data = { { temp = 25.2 }, { temp = 27.1 } } }
-
-
-
(
req
) argument
A Lua table which contains the information about the request. On root level thereq
argument contains the following fields:-
access_token_payload
Optional, holds the payload of the provided JSON Web Token (JWT). -
headers
A Lua table containing the HTTP request headers. -
method
The HTTP method of the request, like DELETE, GET, POST, PUT. -
path
The part of the path after the function name. In case no path is provided the value will be an empty string. -
query
A Lua table which contains the provided URL query parameters. In case no query parameter is provided the value will be an empty Lua table. -
remote_ip_address
The client’s IP Address. -
server_oid
The object id of the Web API Server object, which processes the request. -
context_info
A Lua table which contains the context information of the request. Thectx
field specifies the path of the object in which the script is running. Theprofile
field contains the name of the profile used as security context. Thetopic
field contains the name of the endpoint, likeexecfunction
,read
,write
. In case of an Advanced Endpoint or Exec Function request theexecfunction
field holds a Lua table containing the fieldslib
andfunc
. -
url
A Lua table which contains the full URL (href
) and its componentsprotocol
,hostname
,port
,pathname
and optional thesearch
andhash
.
The advanced endpoint accepts any path. The part of the path after the function name can be accessed by the
path
field of the requestreq
argument. URL query parameters can be accessed by thequery
fields. Thepath
andquery
fields can be used to handle routing withing Lua.`/api/v2/execfunction/corporate/readMachineData/lab/1234`
This will result in the
readMachineData
will be executed of the librarycorporate
where the/lab/1234
can be accessed on thereq.path
parameter.The provided query parameters in the URL are accessible through the
query
field of the requestreq
argument. This field is a Lua table which contains the query parameter names as keys and query parameter values as strings. In case a query parameter is provided more than once this query table contains one entry of which the value is a Lua table string array.The HTTP request type can be accessed by the
method
field. This field contains one of the following string values:DELETE
,GET
,HEAD
,OPTIONS
,PUT
,POST
,PATCH
. -
-
(
hlp
) argument
Thehlp
argument is helper object which contains convenience functions, likecheckpermission
andcreateResponse
.The
createResponse
function can be used to set the response body, error, HTTP status code and response headers, which should be returned by the Web API.Extended explanation and examples of how to use the helper function can be found in the
execfunction endpoint documentation
.
Examples
The Advanced Endpoint can make use of the standard logic in order to e.g. read historical data. This way it is very easy to add custom logic in combination with standard API functionality. Add the code examples to the Script Library of the Web API Server Model object. Name the library "my-lib" and click Apply to save changes.
The standard API logic can be accessed via the syslib.api
Lua library by using require('syslib.api')
to the top of the Script Library in the Web API Server Model object.
To test these examples, please download Postman here. This allows you to make calls to the Web API by constructing query URLs.
Remember to enable Authentication by adding authorization credentials to your URL requests. This can be done in the header of the request. |
Example - Read Historical Data
This simplified example reads historical data for one of the performance counters in which a caller only need to supply a start time.
local inAPI = require('syslib.api')
local lib = {}
function lib:readperfcounters(arg, req, hlp)
arg = arg or {}
local now = syslib.currenttime()
local startTime
if type(arg.starttime) == 'string' then
-- Use starttime supplied by the caller.
startTime = arg.starttime
else
-- Fallback to a default relative starttime
startTime = syslib.gettime(now-(5*60*1000))
end
local endTime = syslib.gettime(now)
local qry = {
start_time = startTime,
end_time = endTime,
intervals_no = 100,
items = {
{
p = "/System/Core/Performance Counter/Core/CPU",
aggregate = "AGG_TYPE_INTERPOLATIVE"
}
}
}
return inAPI:readhistoricaldata(qry, req, hlp)
end
return lib
Invoke this endpoint by:
Method: POST
URL: /api/v2/execfunction/my-lib/readperfcounters
Body:
{
"start_time": "2019-04-02T10:00:00.000Z"
}
Example - Read Raw Historical Data with filter
This example shows how to read raw historical data for one of the performance counters. Start time and a value, which acts as a filter, are the parameters, which need to be supplied by the caller. The filter will only return values, which are greater than or equal to the provided value.
local inAPI = require('syslib.api')
local lib = {}
function lib:readperfcounters(arg, req, hlp)
arg = arg or {}
local now = syslib.currenttime()
local startTime
if type(arg.starttime) == 'string' then
-- Use starttime supplied by the caller.
startTime = arg.starttime
else
-- Fallback to a default relative starttime
startTime = syslib.gettime(now-(5*60*1000))
end
local endTime = syslib.gettime(now)
local qry = {
start_time = startTime,
end_time = endTime,
filter = {
v = {
["$gte"] = arg.limit or 50
}
},
items = {
{
p = "/System/Core/Performance Counter/Core/CPU",
}
}
}
return inAPI:readrawhistoricaldata(qry, req, hlp)
end
return lib
Invoke this endpoint by:
Method: POST
URL: /api/v2/execfunction/my-lib/readperfcounters
Body:
{
"start_time": "2019-04-02T10:00:00.000Z",
"limit": 35
}
Example - Read Raw Historical Data and respond in CSV format
This example shows how to read raw historical data for one of the performance counters. Start time and a value, which acts as a filter,are the parameters, which need to be supplied by the caller. The filter will only return values which are greater than or equal to the provided value. The createResponse
helper function is used to set the Content-Type
of the response body to CSV format.
local inAPI = require('syslib.api')
local lib = {}
function lib:readperfcounters(arg, req, hlp)
arg = arg or {}
local now = syslib.currenttime()
local startTime
if type(arg.starttime) == 'string' then
-- Use starttime supplied by the caller.
startTime = arg.starttime
else
-- Fallback to a default relative starttime
startTime = syslib.gettime(now-(5*60*1000))
end
local endTime = syslib.gettime(now)
local qry = {
start_time = startTime,
end_time = endTime,
filter = {
v = {
["$gte"] = arg.limit or 50
}
},
items = {
{
p = "/System/Core/Performance Counter/Core/CPU",
}
}
}
local respData = {}
local res = inAPI:readrawhistoricaldata(qry, req, hlp)
local rawData = res.data or {}
local histData = rawData.historical_data or {}
local queryData = histData.query_data or {}
if #queryData > 0 then
queryData = queryData[1]
local items = queryData.items or {}
if #items > 0 then
items = items[1]
for i,t in ipairs(items.t) do
local value = items.v[i]
local timestampISO = syslib.gettime(t)
local row = ("%s,%s"):format(timestampISO, value)
table.insert(respData, row)
end
end
end
local result = table.concat(respData, '\n')
return hlp:createResponse(result, nil, 200, { ["Content-Type"] = "text/csv" })
end
return lib
Invoke this endpoint by:
Method: POST
URL: /api/v2/execfunction/my-lib/readperfcounters
Body:
{
"start_time": "2019-04-02T10:00:00.000Z",
"limit": 35
}