@liquicode/lib-mrpc
v0.0.6
Published
A transport agnostic message based remote procedure call library designed to facilitate the evolution and scalability of complex systems.
Downloads
35
Maintainers
Readme
lib-mrpc (v0.0.6)
A transport agnostic message based remote procedure call library designed to facilitate the evolution and scalability of complex systems.
Overview
What this library offers is a base ServiceProvider
class and a number of specific ServiceProvider
implementations where each implementation utilizes a different transport mechanism to provide the
library's remote procedure call functionality.
Examples of different transport mechanisms include http gets and posts, message queues, pub/sub channels, etc.
Each ServiceProvider
allows you to define a number of named Endpoints
that can be invoked by client code.
Each endpoint has function associated with it and is called whenever the Endpoint
is invoked.
The function is passed a set of parameters and its return values and errors are to delivered back
to the client calling code.
The mechanics of packaging and unpackaging parameters, return values, and errors are handled by each
ServiceProvider
implementation.
Installation
npm install --save @liquicode/lib-mrpc
Simple Usage
This simple example creates an ImmediateServiceProvider
, adds a multiply function
to it, and then calls that multiply function.
Since we are using the ImmediateServiceProvider
, the multiply function executes
immediately and returns its value directly to the calling code.
This general pattern is used regardless of which underlying ServiceProvider
implemntation is being used.
// Include the library in your source code.
const lib_mrpc = require( '@liquicode/lib-mrpc' );
// Create a service provider for local development.
let service = lib_mrpc.ImmediateServiceProvider( 'My Service' );
// Activate the service.
service.OpenPort();
// Define a function for the service.
function multiply_function( Parameters )
{
return (Parameters.arg1 * Parameters.arg2);
}
// Add the function to your service.
await service.AddEndpoint( 'Multiply', multiply_function );
// Call the service function.
let result = await service.CallEndpoint( 'My Service', 'Multiply', { arg1: 6, arg2: 7 } );
console.log( '6 * 7 = ' + result ); // 6 * 7 = 42
Remote Functions
This example takes the same functionality (i.e. a multiply function) and lets you
call it remotely via a message queue server that supports the amqp
protocol
(e.g. RabbitMQ).
Remoting the function has minimal impact on your code as all that is required
is to change the type of ServiceProvider
that you use. The function signatures
and mechanics are identical across all types of ServiceProvider
.
server.js:
// Instantiate a ServiceProvider which listens for commands on a message queue server.
const lib_mrpc = require( '@liquicode/lib-mrpc' );
let options = { server: 'amqp://my-rabbitmq' };
let service = lib_mrpc.AmqpLibServiceProvider( 'My Service', options );
service.OpenPort();
// Add the Multiply function to our service.
await service.AddEndpoint( 'Multiply',
( Parameters ) =>
{
return (Parameters.arg1 * Parameters.arg2);
} );
client.js:
// Instantiate a connection to the server via the same message queue.
const lib_mrpc = require( '@liquicode/lib-mrpc' );
let options = { server: 'amqp://my-rabbitmq' };
let service = lib_mrpc.AmqpLibServiceProvider( 'My Service', options );
service.OpenPort();
// Call the service function. This code is identical regardless of which ServiceProvider being used.
let result = await service.CallEndpoint( 'My Service', 'Multiply', { arg1: 6, arg2: 7 } );
console.log( '6 * 7 = ' + result ); // 6 * 7 = 42
Remoting Errors
Just like any other function, an Endpoint
can throw errors (intentional or otherwise).
lib-mrpc
catches these errors and then remotes them back to the calling function.
The following example uses RedisServiceProvider
to communicate with a remote service
via an existing redis server.
In this case, rather than doing something tremendously useful in our Endpoint
, we will just throw an error.
server.js:
const lib_mrpc = require( '@liquicode/lib-mrpc' );
let service = lib_mrpc.RedisServiceProvider( 'My Service', { server: 'redis://my-redis' } );
service.OpenPort();
await service.AddEndpoint(
'Gives Errors',
( Parameters ) =>
{
throw new Error('Error something about something.'); // Just throw an error.
} );
client.js:
const lib_mrpc = require( '@liquicode/lib-mrpc' );
let service = lib_mrpc.RedisServiceProvider( 'My Service', { server: 'redis://my-redis' } );
service.OpenPort();
// Call the service function, expect errors.
try
{
await service.CallEndpoint( 'My Service', 'Gives Errors', {} );
}
catch( error )
{
console.log( error.message ); // "Error something about something."
}
// Or, call the service function and get errors in the callback.
service.CallEndpoint( 'My Service', 'Gives Errors', {},
( error, reply ) =>
{
if( error )
{
console.log( error.message ); // "Error something about something."
}
else
{
console.log( "What am I doing here?" ); // This doesn't get executed.
}
} );