The Barracuda Server's JSON-RPC implementation makes it extremely easy to export Lua functions in the server as JSON-RPC Web Services. The services can be used by any compliant JSON-RPC client stack, including the Barracuda Server JSON-RPC client JavaScript stack.
The Barracuda Embedded Web Server can provide an unlimited number of JSON-RPC services. A JSON-RPC service can be installed at any URL location in the server. Any LSP page can be used as an entry point for JSON-RPC, but you must not generate any content in the page. The JSON-RPC object automatically generates the required response.
<?lsp -- Lua RPC code here. You must not have anything outside <? And ?> ?>
A JSON-RPC service in Barracuda consists of one or several objects. Each object in turn consists of one or several methods. This is equivalent to an object oriented design where one typically calls a method in an object, example: math.subtract(10,5)
As an example, assume we want a math JSON service. The math service provides a math object and methods such as add, subtract, etc..
<?lsp -- (1) Load the JSON-RPC service local jsonrpc=require"jsonrpc" -- (2) Our math.add Web-Services function local function add(a,b) return a + b end -- Our math.subtract Web-Services function local function subtract(a,b) return a - b end -- (3) Create the math web service local mathService = jsonrpc.new("A basic math service", { math={ -- (4) The math Web-Services object add=add, subtract=subtract, } }) -- (5) Execute the web service mathService:execute(request, response) ?>
The following code snippet shows how to load the JSON-RPC stack:
local jsonrpc=require"jsonrpc"
The file json.rpc contains the Lua JSON-RPC stack. The Lua JSON-RPC stack must be made available such that the VM can load this code. The Lua JSON-RPC code is distributed with the Barracuda Server SDK.
JSON-RPC functions are standard Lua functions. The JSON-RPC library automatically decodes the JSON data sent from the client. One can have any number of arguments, and the argument can be of any type. JSON objects are converted to Lua tables.
One can also have a dynamic number of arguments. For example, we can change the "add function" to work with any number of arguments. The following example returns the summation of all its arguments:
local function add(...) local s = 0 for i, v in ipairs{...} do s = s + v end return s end
We are not doing any type checking on the arguments in (2). The Lua VM may throw an exception if the two arguments cannot be added.
You can add argument validation to the code as follows:local function add(a,b) if type(a) ~= "number" then error("The first argument is not a number") end if type(b) ~= "number" then error("The second argument is not a number") end return a + b end
Function "error" generates an exception and the exception message is sent back to the client. Exceptions are thrown all the way back to the client. For example, our JSON-RPC JavaScript library throws an exception if calling a server side function fails. See the JSON-RPC client JavaScript stack for more information.
We now create a JSON-RPC object by calling jsonrpc.new. The function takes two arguments, a string and a table. The Lua table is converted by the JSON-RPC implementation and made available to clients as a Service Description object. Clients supporting introspection, such as our JSON-RPC client JavaScript stack, can automatically provide the functions to the client web-services implementation.
The table must contain at least one sub-table. We mentioned above that a JSON-RPC service in Barracuda consists of one or several objects, where each object in turn consists of one or several methods. This is not an option; you cannot just export the function(s). We have only one object, the math object. The math table contains two functions, add and subtract. A client can now call math.add and math.subtract.
We have so far just declared the functions and created the JSON-RPC object "mathService". We must now execute the Web-Service. We do this by calling the execute method. The execute method takes two arguments, the request object, and the response object. The request and response object are used by the JSON-RPC stack for reading/parsing the request, and sending the response (return value) from your service function. The client JSON-RPC stack cannot parse the response data if you generate any response data outside of the <? and ?>.
You may have noticed that we created a JSON-RPC object (3) every time the client calls one of our Web-Services functions. This is great during development as the LSP compiler recompiles the LSP page automatically if the page has changed. You can optimize the code when you have completed the development by moving all code, except for (5) to the application object. The application object is created when your LSP application starts. The VM executes the .preload script, if found, when you load an LSP application. You can simply move the code into this file when you are done with the development. The LSP script will then only contain one line of code.
<?lsp app.mathService:execute(request, response) ?>
Notice that we must now reference the mathService object via the application object.
In addition to using LSP pages as JSON-RPC services, a directory can be used:
local jsonrpc=require"jsonrpc" local function add(a,b) return a + b end local function subtract(a,b) return a - b end local mathService = jsonrpc.new("A basic math service", { math={ add=subtract, subtract=subtract, } }) local function webservice(dir,func,path) if path ~= "" then -- We have only one service response:senderror(404) else mathService:execute(request, response) end end -- Create directory: "web-service" dir = ba.create.dir("web-service", webservice) ba.dirtop():insert(dir) -- Insert into first root directory