NAME
JRPC::CGI - JSON-RPC 2.0 Processing for CGI and HTTP::Server::Simple::CGI
DESCRIPTION
This package provides JSON-RPC 2.0 services processor for 2 runtimes based on:
CGI (CGI.pm) Plain old CGI scripting (or mod_perl ModPerl::Registry mode)
HTTP::Server::Simple::CGI - a fast and lightweight runtime with a Perl embedded httpd (web server) module.
HTTP::Server::Simple::CGI is especially interesting for doing distributed computation over the http.
METHODS
Because of the rudimentary nature of CGI (in both good and bad), the JRPC::CGI::handle_cgi($cgi) is to be called explicitly in code (as CGI is not hosted by sophisticated server).
The service method JRPC::CGI::handle_simple_server_cgi($server, $cgi); for HTTP::Server::Simple::CGI can be aliased to local package's handle_request method, which is the request handling method for HTTP::Server::Simple framework (similar to mod_perl's and Nginx's handler($r) method).
JRPC::CGI::handle_cgi($cgi)
Traditional CGI Handler for JRPC. Example CGI wrapper:
#!/usr/bin/perl
use CGI;
use CGI::Carp qw/fatalsToBrowser warningsToBrowser/;
use JRPC::CGI;
use SvcTest; # Load Service package
my $cgi = CGI->new();
# Process request. Reports all errors to Client as a JSON-RPC error (fault) response.
JRPC::CGI::handle_cgi($cgi);
exit(0);
# This "Service Package" could (and should) be in a separate file (SvcTest.pm).
# It will be called back by JRPC.
package SvcTest;
use Scalar::Util ('reftype');
# Simpliest possible service:
# - reflect/echo 'params' (of request) to 'result' (of response)
# - Framework will take care of request parsing and response serialization
# - On validation errors, Framework will turn a Perl exception to a JSON-RPC fault.
# Call this by: ..., "method": "Test.echo", ...
sub echo {
my ($p, $jrpc) = @_;
# Validate, require $p to be HASH (ref).
# Framework will convert exceptions to JSON-RPC Fault
if (reftype($p) ne 'HASH') {die("param was not found to be a JSON Object");}
return($p);
}
1;
JRPC::CGI::handle_simple_server_cgi($server, $cgi);
Wrapper for intercepting a request to HTTP::Server::Simple::CGI.
Alias this as a handle_request() in your package implementing
HTTP::Server::Simple::CGI. Example:
#!/usr/bin/perl
{
package MyJRPC;
use HTTP::Server::Simple::CGI;
use base 'HTTP::Server::Simple::CGI';
# Reuse handle_simple_server_cgi, assign as local alias.
*handle_request = \&JRPC::CGI::handle_simple_server_cgi;
}
my $port = $ENV{'HTTP_SIMPLE_PORT'} || 8080;
my $pid = MyWebServer->new($port);
#my $pid = MyWebServer->new($port)->background();
print "Use 'kill $pid' to stop server (on port $port).\n";
RUNNING SERVER IN THREAD
To be able to run server in thread and to be able to terminate the thread, use the following idiom:
# Server thread as anonymous sub. Pass port to run at.
my $runmyserver = sub {
my ($port) = @_;
# Use signaling to kill thread
$SIG{'KILL'} = sub { threads->exit(); };
# Run in the same process, NOT spawning a sub process.
MyServer->new($port)->run();
};
my $thr = threads->create($runmyserver, $port);
# ...
# Much later ... terminate server as no more needed.
$thr->kill('KILL')->detach();
# This main thread should continue / survive beyond this point ...
HINTS
JSON-RPC is not a domain for obsessed print(); debugging folks. Printing to STDOUT messes up the JSON-RPC response output. The returned data structure gets automatically converted to a successful JSON-RPC Response (data goes into 'result' member). Any fatal errors thrown as Perl exceptions get automatically converted to a valid JSON-RPC exception / fault (member 'error', and optionally to logs). Any diagnostic messaging goes to response or logs (or both), NOT STDOUT.
TODO
Private package (file) for ServerSimple (with direct default handler handle_request())?
In private package use HTTP::Server::Simple::CGI (and inherit from it)