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 )