package JSON::RPC::Parser; use strict; use JSON::RPC::Procedure; use Carp (); use Plack::Request; use Class::Accessor::Lite new => 1, rw => [ qw( coder ) ] ; sub construct_procedure { my $self = shift; JSON::RPC::Procedure->new( @_ ); } sub construct_from_req { my ($self, $req) = @_; my $method = $req->method; my $proc; if ($method eq 'POST') { $proc = $self->construct_from_post_req( $req ); } elsif ($method eq 'GET') { $proc = $self->construct_from_get_req( $req ); } else { Carp::croak( "Invalid method: $method" ); } return $proc; } sub construct_from_post_req { my ($self, $req) = @_; my $request = eval { $self->coder->decode( $req->content ) }; if ($@) { Carp::croak( "JSON parse error: $@" ); } my $ref = ref $request; if ($ref ne 'ARRAY') { # is not a batch request return $self->construct_procedure( method => $request->{method}, id => $request->{id}, params => $request->{params}, jsonrpc => $request->{jsonrpc}, has_id => exists $request->{id}, ); } my @procs; foreach my $req ( @$request ) { Carp::croak( "Invalid parameter") unless ref $req eq 'HASH'; push @procs, $self->construct_procedure( method => $req->{method}, id => $req->{id}, params => $req->{params}, jsonrpc => $req->{jsonrpc}, has_id => exists $req->{id}, # when not true it's a notification in JSON-RPC 2.0 ); } return \@procs; } sub construct_from_get_req { my ($self, $req) = @_; my $params = $req->query_parameters; my $decoded_params; if ($params->{params}) { $decoded_params = eval { $self->coder->decode( $params->{params} ) }; } return $self->construct_procedure( method => $params->{method}, id => $params->{id}, params => $decoded_params, jsonrpc => $params->{jsonrpc}, has_id => exists $params->{id}, ); } 1; __END__ =head1 NAME JSON::RPC::Parser - Parse JSON RPC Requests from Plack::Request =head1 SYNOPSIS use JSON::RPC::Parser; my $parser = JSON::RPC::Parser->new( coder => JSON->new ); my $procedure = $parser->construct_from_req( $request ); =head1 DESCRIPTION Constructs a L object from a Plack::Request object =cut