Catalyst-Plugin-JSONRPC-Server
view release on metacpan or search on metacpan
lib/Catalyst/Plugin/JSONRPC/Server/Dispatcher.pm view on Meta::CPAN
package Catalyst::Plugin::JSONRPC::Server::Dispatcher;
use v5.36;
use Moo;
use JSON::MaybeXS ();
use Try::Tiny;
use Carp qw/croak/;
use Scalar::Util qw/blessed/;
use Catalyst::Plugin::JSONRPC::Server::Error;
use namespace::clean;
our $VERSION = '0.003';
=encoding utf8
=head1 NAME
Catalyst::Plugin::JSONRPC::Server::Dispatcher - pure JSON-RPC 2.0 protocol engine
=head1 DESCRIPTION
The Catalyst-free engine behind L<Catalyst::Plugin::JSONRPC::Server>: it parses
and validates JSON-RPC 2.0 envelopes (single and batch), routes to registered
handlers, and produces spec-compliant result/error responses. It has no
knowledge of Catalyst or of any application domain.
=cut
has _handlers => ( is => 'ro', default => sub { {} } );
has _json => (
is => 'lazy',
# allow_nonref is REQUIRED: a top-level JSON scalar (e.g. '"x"' or '1') is
# valid JSON per RFC 8259, and must decode so dispatch() can reject it as a
# non-object with -32600 (Invalid Request). Without it, backends that
# default allow_nonref off (JSON::XS, older JSON::PP/Cpanel::JSON::XS) throw
# on decode, misreporting -32700 (Parse error). Seen as a CPAN Testers
# failure of t/dispatcher-errors.t "non-object request is invalid".
builder =>
sub { JSON::MaybeXS->new( utf8 => 1, canonical => 1, allow_nonref => 1 ) },
);
# Maximum number of elements accepted in a batch array; 0 = unlimited. A finite
# default caps the trivial amplification of a huge batch in one small body,
# while staying generous enough for any realistic client.
has max_batch => ( is => 'ro', default => 1000 );
sub register ( $self, $method, $code ) {
croak "JSON-RPC method must be a non-empty string"
if !defined $method || ref $method || !length $method;
croak "JSON-RPC handler must be a CODE ref"
unless ref $code eq 'CODE';
$self->_handlers->{$method} = $code;
return $self;
}
sub encode ( $self, $data ) {
return $self->_json->encode($data);
}
# Like encode(), but never dies on a non-serializable value. A handler that
# returns something the JSON codec can't encode (a blessed object without
# TO_JSON, a coderef, a cyclic structure) would otherwise die here, outside the
# per-handler try/catch, and 500 the whole request/batch. Instead, salvage: any
# response element that won't encode is replaced by a -32603 (its id preserved),
# so one bad result can't take down the others.
sub encode_safe ( $self, $data ) {
( run in 1.429 second using v1.01-cache-2.11-cpan-5fbc6bb55f2 )