For some reason XML-RPC has been taking up a lot of my thoughts lately. I've been thinking of a nice way to create an API to perl subroutines.

I wanted to create something where the the packages within the API itself would have to do little XML RPC related work themselves.

The main guts of the XML RPC would would come in this file

package XMLMethod; use Server; use RPC::XML::Procedure; sub import { my $child = shift; print "Child is $child\n"; return if $child eq 'XMLMethod'; my $export_procedures = *{"$child\::export_procedures"}{CODE}; die "$child does not implement export_procedures method\n" unless +$export_procedures; #run the code my $import_proc = &$export_procedures; my @procedures; while (my ($identifier, $details) = each(%{$import_proc}) ) { my $sub_ref = $details->[0]; my $sig = $details->[1]; my $proc = RPC::XML::Procedure->new({ 'name' => $id +entifier, 'code' => $su +b_ref, 'signature' => + [$sig] }); push(@procedures,$proc); } foreach (@procedures) { $Server::server->add_method($_); } } 1;
This XMLMethod package will look at every package which imports it and will look for the export_procedures sub. This sub essentially returns the code reference, signature and an identifier in a hash ref. I looked into automating this, by using no strict 'refs' and going through the package symbol table, but thought it might be problematic discerning what is actually a sub that is intended to be used in the XML RPC and what is not. So I decided it would be better to explicitly set the details from within each individual package. The following is an example of a package which would be in the API Directory.
package API::Math; use base XMLMethod; sub export_procedures { my %subs = ( 'math.sum' => [\&API::Math::sum, 'int int int'] ); return \%subs; } sub sum{ my $x = shift; my $y = shift; return $y + $x; } 1;

What I like about it the most, is that all you need to do is make sure your export_procedures sub is correct, and then use XMLMethod and then you will have your code available to respond to XML RPC requests without having to worry about anything else.

Does anybody feel there are any large oversights or omissions? Ideas for how it could be done in a 'nicer' way?

Ray

Replies are listed 'Best First'.
Re: XML-RPC API layout
by jdrago_999 (Hermit) on Jul 21, 2009 at 17:34 UTC
    Does anybody feel there are any large oversights or omissions?

    I might replace the export_procedures sub with something more declarative. Also, it would be nice to *not* have to use base 'XMLMethod';. Something like:

    package MyPackage; use strict; use warnings 'all'; # This would import rpc_method into the current namespace: use XMLMethod 'rpc_method'; # Declare a method as rpc-able: rpc_method( 'math.sum', \&API::Math::sum, [qw/ int int int /] ); # Or maybe: rpc_method name => 'math.sum', method => \&API::Math::sum, signature => [qw/ @int /]; rpc_method name => 'math.avg', method => \&API::Math::avg, signature => [qw/ @int /]; rpc_method name => 'string.join', method => \&join, signature => [qw/ @str /];

      Yes I think that *not* having to use XMLMethod as the base and simply calling a subroutine of XMLMethod would make it easier to understand what is happening and more readable in general.

      Originally when I wrote I was envisioning not having to have anything obviously rpc related in the MyPackage bit, other than use base XMLMethod. This, for me, would have been very elegant. Have a package with a set of subroutines, add the use base XMLMethod and whallah, the package is now set up for xml rpc.

      I felt I couldn't do this reliably though, so I conceeded making the export_procedures sub. I guess the export_procedures sub is not as declarative as something like the rpc_method you suggested, and If I'm going to abandon the original idea of how the XMLMethod should work then maybe there is no point in 'kinda sorta' implementing in the manner it is currently.