Hosted by Three Crickets

Diligence
Web Framework
For Prudence and MongoDB

Diligence is still under development and incomplete, and some this documentation is wrong. For a more comprehensive but experimental version download the Savory Framework, which was the preview release of Diligence.

Diligence logo: sleeping monkey

RPC Service

The RPC (Remote Procedure Call) Service provides robust, elegant support for various versions of the JSON-RPC and XML-RPC specifications, including support for batch processing for JSON-RPC 2.0. It's powerful enough that it may be in itself the primary reason why you wish to use Diligence.
In most cases, all you need to do is hookup your JavaScript functions to a URI, and let the RPC Service do the rest. All error codes, system APIs and type conversions will be properly handled.
As a bonus, the RPC Service also includes a nice client utility for calling JSON-RPC and XML-RPC.
Is RPC a good idea? We're inclined to say: no. REST is a much more scalable and robust pattern, all things considered. REST uses all the power of HTTP to provide client-cacheable representations. RPC, on the other hand, supports only HTTP POST, the only non-idempotent HTTP operation, which can never be cached. However, RPC may be necessary for communication with other services and clients, so you might not have a choice. And, sometimes, it's just the most straightforward, quick-and-dirty solution to a problem. Especially with the Diligence RPC Service, it's so easy to just allow clients to call functions on the server, that sometimes you might prefer it to designing a RESTful URI-space. So be it! Just make sure you understand the pros and cons of you choice.

Setup

Make sure to check out the API documentation for Diligence.RPC.
First, let's configure the URI-space in your application's "routing.js". Add the following to app.routes and app.dispatchers:
app.routes = {
	...
	'/calc/': '@calc'
}
​
app.dispatchers = {
	...
	javascript: '/manual-resources/'
}
We can now configure our resources in "/libraries/manual-resources.js":
document.executeOnce('/diligence/service/rpc/')
​
var Calc = {
	multiply: function(x, y) {
		return x y
	}
}
​
resources = {
	...
	calc: new Diligence.RPC.Resource({namespaces: {Calc: Calc}})
}
And… that's pretty much it! You can now call your methods using JSON-RPC or XML-RPC.

Namespaces

The key of the namespace is prefixed with a period before all method identifiers. So, our method above would be identified as "Calc.multiply".
However, if you do not want this prefix, you can use the special "." key, which here means the root namespace:
resources = {
	...
	calc: new Diligence.RPC.Resource({'.': Calc})
}
The method would now be identified simply as "multiply".
If you don't need the namespaces feature at all, you can use the following shortcut (note the "namespace" key, singular):
resources = {
	...
	calc: new Diligence.RPC.Resource({namespace: Calc})
}

Long Form

You have some more control over the exported functions, should you need it. The long form of creating namespaces is like so:
var Calc = {
	multiply: {
		fn: function(x, y) {
			return x y
		},
		arity: 2
	}
}
The "artity" key counts how many arguments the function requires. If it's not there, the RPC Service will count them from the function spec. However, this won't work if you access JavaScript "arguments" directly, hence this long form exists.

System Namespace

The "system" namespace is reserved for parts of the RPC protocols. The RPC Service implements these for you:

Scope

When your function is called, the "this" will be automatically populated with the following keys:
The "method" key is useful in that you can add anything you want to the method object. For a rather silly example:
var Calc = {
	multiply: {
		fn: function(x, y) {
			return x y this.definition.multiplyAll
		},
		multiplyAll: 100
	}
}
One special key is reserved: "scope". Use it to override "this" to be any value you desire:
var Calc = {
	multiply: {
		fn: function(x, y) {
			return x y this
		},
		scope: 100
	}
}
If you are using JavaScript object oriented programming, you might want "this" to always just be the namespace object itself. In that case, you can use the "objects" key instead of the "namespaces" key when creating your Diligence.RPC.Resource constructor. It works the same way as a namespace except that the scope will be the object itself for all method calls:
// This is a class
var Calc = function(multiplyAll) {
	this.multiplyAll = multiplyAll
​
	this.multiply = function(x, y) {
		return x y this.multiplyAll
	}
}
​
resources = {
	...
	calc: new Diligence.RPC.Resource({objects: {Calc: new Calc(100)}})
}
You can mix "namespaces" and "objects" in the same constructor. Also note that you can also use "object" (singular) in the same way as "namespace" (singular).

Fault Codes

If your function throws an exception, the RPC Service will return a ServerError fault code with the exception string as the message.
However, you can also return specific XML-RPC fault codes (the same code numbers are used by JSON-RPC):

Usage

URI Query Parameters

Calling RPC with the API

The RPC Service includes a useful RPC client function, "Diligence.RPC.request". It's essentially a wrapper over the Prudence.Resources API that builds the payload for you and nicely unpacks the results. The results will always be in JSON-RPC's format, even if you are using XML-RPC. This allows for uniform processing on your end.
Here's an example of an internal call using JSON-RPC:
document.executeOnce('/diligence/service/rpc/')
​
var result = Diligence.RPC.request({
	uri: '/calc/',
	internal: true,
	name: 'Calc.multiply',
	params: [5, 6],
	id: 'abc',
	protocol: 'json'
})
​
if (result.error) {
	print('Error: ' + result.error.message)
}
else {
	print(result.result)
}
For XML-RPC, simply set "protocol" to "xml". If not provided, it defaults to "json". Note that the result will also include that "protocol" key you provided, in case you need to know which protocol was used.
Generally, if you have the option to use JSON-RPC, you should prefer it. XML serialization incurs an extra overhead in JavaScript.

Calling RPC with cURL

cURL is an HTTP command line tool based on the cURL library, available for a great many Unix-like operating systems as well as Windows. It's especially useful for testing RESTful APIs. Here's a quick tutorial to get you started with using cURL with the RPC Service.
First, let's create our payload. With a text editor, create a file named "rpc.json" and paste this:
{
	"jsonrpc": "2.0",
	"method": "Calc.multiply",
	"params": [2, 3],
	"id": "abc"
}
You can send a payload using the "-d" switch, which also sets the HTTP verb to POST. When using "-d", you can also start your payload with "@" to signify that you want to send the contents of a file:
curl -d @rpc.json "http://localhost:8080/myapp/calc/?type=json&human=true"
You should get this result:
{
	"id": "abc",
	"result": "6",
	"error": null,
	"jsonrpc": "2.0"
}

Calling RPC from Web Browsers

Many client-side JavaScript frameworks include support for RPC, but if all you need is a straightforward, self-contained library, we recommend jsonrpcjs.

The Diligence Manual is provided for you under the terms of the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. The complete manual is available for download as a PDF.

Download manual as PDF Creative Commons License