The Perl and Raku Conference 2025: Greenville, South Carolina - June 27-29 Learn more

#! perl -I. -w
use Dancer qw/!pass !warning/;
my $ENDPOINT = '/system/code_wrapper';
my $UNKNOWN_ENDPOINT = '/system/code_wrapper/undefined_endpoint';
my $client = MyTest::Client->new(ping_value => 'pong');
my $dispatch = {
'MyTest::API' => MyTest::API->new(test_client => $client),
};
my $config = {
config => 'config',
code_wrapper => sub {
my ($code, $package, $method_name, @arguments) = @_;
my $result = eval {
my $instance = $dispatch->{$package};
$instance->$code(@arguments);
};
if (my $error = $@) {
error("[code_wrapper] ($package\->$method_name) ", $error);
if (blessed($error) and $error->does('MyTest::Exception')) {
# The plugin will send a proper error-response for the protocol
die $error->as_string;
}
die $error;
};
return [ $result ];
},
};
set(
plugins => {
'RPC::JSONRPC' => {
$ENDPOINT => {
'MyTest::API' => {
'system_ping' => 'rpc_ping',
'system.exception' => 'rpc_fail',
}
}
}
}
);
set( clients => { test_client => { endpoint => 'somewhere' } });
jsonrpc $ENDPOINT => $config;
note("Without catchall unknown endpoint errors");
{
my $prefix = "Without catchall";
my $response = _post($ENDPOINT);
is($response->{status}, 200, "$prefix: Known endpoint returns 200 status");
is_deeply(
$response->{content}{result},
[ { result => 'pong' } ],
"$prefix: Known route returns result"
);
$response = _post($UNKNOWN_ENDPOINT);
route_doesnt_exist(
[POST => $UNKNOWN_ENDPOINT],
"$prefix: Unknown route $UNKNOWN_ENDPOINT"
);
is($response->{status}, 404, "$prefix: unknown endpoint returns 404 status");
$response = _post(
$ENDPOINT,
{ jsonrpc => "2.0", id => 4242, method => 'system_pong'}
);
is($response->{status}, 200, "$prefix: Unknown method returns 200 status");
is(
$response->{content}{error}{code},
-32601,
"$prefix: Unknown method returns -32601 code"
);
}
setup_default_route();
note('With catchall unknown endpoint errors');
{
my $prefix = "With catchall";
my $response = _post($ENDPOINT);
is($response->{status}, 200, "$prefix: known endpoint returns 200 status");
is_deeply(
$response->{content}{result},
[ { result => 'pong'} ],
"$prefix: Known route returns result"
);
route_exists([POST => $UNKNOWN_ENDPOINT], "$prefix: Known route: $UNKNOWN_ENDPOINT");
$response = _post($UNKNOWN_ENDPOINT);
is($response->{status}, 200, "$prefix: Unknown route returns 200 status");
is_deeply(
$response->{content}{error},
{
code => -32601,
message => "Method 'system_ping' not found",
},
"$prefix: Unknown route returns -32601 error"
);
route_exists([POST => $UNKNOWN_ENDPOINT], "$prefix: Known route $UNKNOWN_ENDPOINT");
$response = _post(
$ENDPOINT,
{ jsonrpc => "2.0", id => 424242, method => 'system.pong' }
);
is($response->{status}, 200, "$prefix: Unknown method returns 200 status");
is(
$response->{content}{error}{code},
-32601,
"$prefix: Unknown method returns -32601 code"
);
like(
$response->{content}{error}{message},
qr/Method '.*' not found/,
sprintf("RPC::JSONRPC: %s - %s", $prefix, $response->{content}{error}{message}),
);
}
done_testing();
sub _post {
my ($endpoint, $body) = @_;
$body //= { jsonrpc => "2.0", id => "42", method => 'system_ping' };
my $request = to_json($body);
my $response = dancer_response(
POST => $endpoint,
{
content_type => 'application/json',
body => $request,
}
);
if ($response->{headers}{'content-type'} eq 'application/json') {
$response->{content} = from_json($response->{content})
}
return $response;
}