Copyright © 2007-2010, 2011, 2012 Tony Garnock-Jones and 2007-2010 LShift Ltd.
Introduced in: 1.2.0
Authors: Tony Garnock-Jones (tonygarnockjones@gmail.com), LShift Ltd. (query@lshift.net).
References
Provides a registry of running JSON-RPC objects, and a transport-neutral means of invoking methods defined on such objects.
Other modules provide interfaces to specific transports and
transport implementations. See rfc4627_jsonrpc_http
and
rfc4627_jsonrpc_inets
, for example.
In the normal case, each JSON-RPC object in a running system corresponds to one Erlang process. This makes object lifecycle control very natural.
Ensure the registry process is running, using start/0
or
start_link/0
. Once it's up and running, use register_service/2
to expose a process as a JSON-RPC service.
To register a service, you will need to describe the methods
available on it. Use service/4
to do so.
Your service should be implemented by a gen_server
process. JSON-RPC requests will be sent to it as
gen_server:call/2
messages:
{jsonrpc, ProcedureNameBin, RequestInfo, Args}
Your module's handle_call
function should respond to these
messages with a reply of type jsonrpc_response()
.
Here's the implementation of the "test_proc" example:
handle_call({jsonrpc, <<"test_proc">>, _RequestInfo, [Value]}, _From, State) -> {reply, {result, <<"ErlangServer: ", Value/binary>>}, State}.
See also the complete example Erlang module included with the
source code, test_jsonrpc_inets.erl
.
You will need to -include("rfc4627_jsonrpc.hrl").
(Or, if
you've installed the compiled rfc4627_jsonrpc
code in your Erlang
lib directory,
-include_lib("rfc4627/include/rfc4627_jsonrpc.hrl").
)
The service registry must be started before any registrations can
be performed: simply call start/0
or start_link/0
. This will start the registry if it wasn't running,
or if it was, it will inform you of the existing registry's Pid.
Registering a service is as simple as starting a process to receive
service requests, and passing its pid to rfc4627_jsonrpc
along
with a service
descriptor object built from Erlang records defined in
mod_jsonrpc.hrl
:
{ok, Pid} = gen_server:start(?MODULE, [], []), rfc4627_jsonrpc:register_service (Pid, rfc4627_jsonrpc:service(<<"test">>, <<"urn:uuid:afe1b4b5-23b0-4964-a74a-9168535c96b2">>, <<"1.0">>, [#service_proc{name = <<"test_proc">>, idempotent = true, params = [#service_proc_param{name = <<"value">>, type = <<"str">>}]}])).
This code registers a service called "test":
Note that almost all of the string values are expressed as
binaries: this is because rfc4627
uses binaries to
represent JSON strings.
To register a service with multiple procedures, add additional
#service_proc
records to the procedure list in the call to service/4
. Similarly, additional parameters for each procedure can
be defined by the addition of extra #service_proc_param
records
in the appropriate place.
The available types for parameters are the strings defined in this
part of the JSON-RPC specification, namely "bit", "num", "str",
"arr", "obj", "any" or "nil". See also
rfc4627_jsonrpc:proc_param_type/1
.
Usually, JSON-RPC services are invoked via HTTP using rfc4627_jsonrpc_inets
or similar. However, the interface used by
specific network transports to call methods on services is also
available to ordinary programs. (And, of course, programs that
implement new kinds of network transport for JSON-RPC.)
To invoke a local service method, first retrieve its service
descriptor using lookup_service/1
. Then use jsonrpc_post/3
or invoke_service_method/8
to call a method
on the service.
The service record as retrieved from the registry contains the pid of the process responsible for handling service requests.
Instead of registering a pid with the rfc4627_jsonrpc
registry, an alternative is to use a service record with a
function object instead of a pid. This allows more control over
how a service is implemented: if using a gen_server
service is too heavy, a function object that sends a simple
message could be used; or if the service didn't need an
implementing process at all, the function object could process
the request without sending any messages at all.
To build a service descriptor object with a function handler
instead of a pid, call rfc4627_jsonrpc:service/5
instead of rfc4627_jsonrpc:service/4
:
rfc4627_jsonrpc:service({function, fun my_handler/3}, Name, Id, Version, Procs) -> service descriptor object my_handler(ProcedureNameBin, RequestInfo, Args) -> jsonrpc_response()The resulting service descriptor can be registered with
register_service/1
as well as used directly with invoke_service_method/8
.
json() = rfc4627:json()
A JSON value.
jsonarray() = rfc4627:jsonarray()
A JSON array.
jsonobj() = rfc4627:jsonobj()
A JSON "object" or "struct".
jsonrpc_response() = {result | error, json()} | {result | error, json(), jsonobj()}
The type that JSON-RPC service implementations are required to return.
The first value should be result
for a normal return value, or
error
for an error response. Use error_response/2
or
error_response/3
to construct approprate error response
values.
The second value is the main response body: for normal returns, this is the ordinary return value of the procedure, and for error responses, it is the response structure defined in the JSON-RPC specification.
The third, optional, value is calledResponseInfo
. It can be used
by the service implementation to supply transport-specific
information back to its caller. For instance, if invoked via HTTP,
extra headers to send back to the HTTP client can be passed in the
ResponseInfo
object. If ResponseInfo
is omitted, {obj, []}
is
assumed.
service() = #service{}
A service description record, as
defined in rfc4627_jsonrpc.hrl
. Can be constructed using service/4
, or retrieved from the registry using lookup_service/1
.
error_response/2 | Constructs an error response as per the JSON-RPC specification. |
error_response/3 | Constructs an error response as per the JSON-RPC specification. |
expand_jsonrpc_reply/2 | |
gen_object_name/0 | Generates a unique name that can be used for otherwise unnamed JSON-RPC services. |
invoke_service_method/8 | Calls a method defined on a JSON-RPC service. |
jsonrpc_post/3 | Calls jsonrpc_post/4 with a Timeout of default . |
jsonrpc_post/4 | Performs a POST-style invocation of a JSON-RPC service method. |
lookup_service/1 | Calls the registry to look up a service by name. |
proc/2 | Constructs a service procedure description record. |
register_service/1 | Registers a JSON-RPC service. |
register_service/2 | Registers a JSON-RPC service. |
service/4 | Constructs a service description record. |
service/5 | As for service/4 , but supplying a handler for use with
an experimental "stateless" service implementation. |
start/0 | Starts the registry process. |
start_link/0 | Starts the registry process, linking it to the calling process. |
system_describe/2 | Builds a JSON-RPC service description JSON object. |
error_response(CodeOrMessage::integer() | string() | binary(), ErrorValue::json()) -> {error, jsonobj()}
Constructs an error response as per the JSON-RPC specification.
Either a code or a message can be supplied as the first argument.See also: error_response/3.
error_response(Code::integer(), Message::string() | binary(), ErrorValue::json()) -> {error, jsonobj()}
Constructs an error response as per the JSON-RPC specification.
The first argument should hold the error code. Error codes are defined in the JSON-RPC specification.
The second argument can be either a string()
or a binary()
describing the error as text.
expand_jsonrpc_reply(RequestId, X2) -> any()
gen_object_name() -> string()
Generates a unique name that can be used for otherwise unnamed JSON-RPC services.
invoke_service_method(ServiceRec, RequestId, PostOrGet, RequestInfo, EndpointAddress, Method, Args, Timeout) -> jsonrpc_response()
Calls a method defined on a JSON-RPC service.
Use lookup_service/1
or service/5
to get a usable
#service record for use with this function.
The request ID should be the ID from the JSON-RPC request, as it
was encoded for the transport the request arrived on. It will be
used by this function in constructing the JSON-RPC reply
object. Since the request ID is optional, it is acceptable to
supply null
instead of an integer.
The PostOrGet
parameter is used to check the idempotency setting
for the chosen service procedure. If the parameter is passed as
post
, no check is performed, as it is assumed that a stateful
method call is permitted; if it is passed as get
, then the
idempotency flag is checked, and an error object may be returned in
the case that the invoked method is non-idempotent.
The RequestInfo
structure contains transport-specific details
about the request. For HTTP, for example, this will include the
HTTP headers and HTTP method. For AMQP, it will include the
exchange and routing-key.
The EndpointAddress
is only used in the case that the method
being invoked is system.describe
, in which case it is
incorporated into the returned description as detailed in the
documentation for system_describe/2
.
Method
is the name of the service method to invoke, and Args
is
either a JSON "object" or a JSON array, to serve as the parameters
for the call.
Timeout
parameter is used to control how long the system will
wait for a reply from the backing gen_server. If default
is
specified, the default gen_server:call
timeout is used;
otherwise, infinity
or a number of milliseconds is passed in to
the gen_server:call
.
jsonrpc_post(ServiceRec::service(), RequestInfo::jsonobj(), RequestObj::jsonobj()) -> jsonrpc_response()
Calls jsonrpc_post/4
with a Timeout
of default
.
jsonrpc_post(ServiceRec::service(), RequestInfo::jsonobj(), RequestObj::jsonobj(), Timeout) -> jsonrpc_response()
Performs a POST-style invocation of a JSON-RPC service method.
RequestObj
is to be a JSON "object" containing at minimum fields
named "id", "method" and "params", with meanings as defined by the
JSON-RPC specification.
invoke_service_method/8
for descriptions of the other
parameters.
lookup_service(Service::binary()) -> not_found | service()
Calls the registry to look up a service by name.
proc(Name, Params::[Parameter]) -> #service_proc{}
Constructs a service procedure description record.
register_service(ServiceDescription::service()) -> ok
Registers a JSON-RPC service.
The name of the service is contained within its service record.register_service(Pid::pid(), ServiceDescription::service()) -> ok
Registers a JSON-RPC service.
The name of the service is contained within its service record.service(Name, Id, Version, Procs) -> service()
Constructs a service description record.
TheProcs
parameter should be a list of procedure-descriptions,
which can be either constructed manually or using proc/2
.
service(Handler, Name, Id, Version, Procs) -> service()
As for service/4
, but supplying a handler for use with
an experimental "stateless" service implementation.
start() -> {ok, pid()} | {error, {already_started, pid()}}
Starts the registry process.
start_link() -> {ok, pid()} | {error, {already_started, pid()}}
Starts the registry process, linking it to the calling process.
Builds a JSON-RPC service description JSON object.
This is used in the implementation of the system.describe
JSON-RPC method that all JSON-RPC services are required by the
specification to support.
EndpointAddress
is undefined
, no address
field is returned
in the resulting description. Otherwise, it is included
verbatim. The other fields in the description are constructed using
the information in the Service
record.
Generated by EDoc, Nov 21 2012, 14:49:54.