NAME

RPC::ExtDirect - Expose Perl code to JavaScript web applications through Ext.Direct remoting

SYNOPSIS

package Foo::Bar;
   
use Carp;

use RPC::ExtDirect Action => 'Fubar';

sub foo : ExtDirect(2) {
   my ($class, $arg1, $arg2) = @_;
 
   # do something, store results in scalar
   my $result = ...;
 
   return $result;
}
 
sub bar : ExtDirect(params => [foo, bar]) {
   my ($class, %arg) = @_;
 
   my $foo = $arg{foo};
   my $bar = $arg{bar};
 
   # do something, returning scalar
   my $result = [ ... ];
 
   # or throw an exception if something's not right
   croak "Houston, we've got a problem" if $error;
 
   return $result;
}
 
sub baz : ExtDirect(formHandler) {
   my ($class, %arg) = @_;
 
   my @form_fields    =  { grep !/^file_uploads$/ }, keys %arg;
   my @uploaded_files = @{ $arg{file_uploads}     };
 
   # do something with form fields and files
   my $result = { ... };
 
   return $result;
}

DESCRIPTION

Abstract

This module provides easy way to map class methods to ExtDirect RPC interface used with ExtJS JavaScript framework.

What is this for?

There are many RPC protocols out there; ExtJS framework provides yet another one called Ext.Direct. In short, Ext.Direct is a way to call server side code from client side without having to mess with HTML, forms and stuff like that. Besides forward asynchronous data stream (client calls server), Ext.Direct also provides mechanism for backward (server to client) asynchronous event generation.

For more detailed explanation, see http://www.sencha.com/products/extjs/extdirect/.

Terminology

Ext.Direct uses the following terms, followed by their descriptions: Configuration - Description of server side calls exposed to client side. Includes information on Action and Method names, as well as argument number and/or names.

API            - JavaScript code that encodes Configuration.
                 Usually generated on the fly by server side
                 script called by client once upon startup.

Router         - Server side component that receives remoting
                 calls, dispatches requests, collects and
                 returns call results.

Action         - Namespace unit; collection of Methods. The
                 nearest Perl analog is package, other 
                 languages may call it a Class. Since the
                 actual calling code is JavaScript, Action
                 names should conform to JavaScript naming
                 rules (i.e. no ::, use dot instead).

Method         - Subroutine exposed through Ext.Direct API
                 to be called by client side. Method is
                 fully qualified by Action and Method names
                 using dot as delimiter: Action.Method.

Result         - Any data returned by Method upon successful
                 call completion.

Exception      - An error, or any other unwanted condition
                 on server side. Unlike Results, Exceptions
                 are not considered successful; Ext.Direct
                 provides mechanism for managing Exceptions.
 
Event          - An asynchronous notification that can be
                 generated by server side and passed to
                 client side, resulting in some reaction.

Event Provider - Server side script that gets polled by
                 client side every N seconds; default N
                 is 3 but it can be changed.

Using RPC::ExtDirect

In order to export subroutine to ExtDirect interface, use ExtDirect(n) attribute in sub's declaration. Note that there can be no space between attribute name and opening parentheses. n is mandatory calling convention declaration; it may be one of the following options: - Number of arguments to be passed as ordered list - Names of arguments to be passed as hash - formHandler that will receive hash of fields and uploaded files - pollHandler does not receive any arguments

Unlike Ext.Direct specification (and reference PHP implementation, too) RPC::ExtDirect does not impose any calling convention on server side code, except bare minimum. There are no "before" and "after" handlers, no object instantiation and no assumptions about the code called. That said, an RPC::ExtDirect Method should conform to the following conventions: - Be a package (Class) method, i.e. be aware that its first argument will be package name. Just ignore it if you don't want it.

   - Ordered (numbered) arguments are passed as list in @_, so
     $_[1] is the first argument. No more than number of arguments
     declared in ExtDirect attribute will be passed to Method; any
     extra will be dropped silently. Less actual arguments than
     declared will result in Exception returned to client side,
     and Method never gets called.

   - Named arguments are passed as hash in @_. No arguments other
     than declared will be passed to Method; extra arguments will
     be dropped silently. If not all arguments are present in
     actual call, an Exception will be returned and Method never
     gets called.

   - Form handlers are passed their arguments as hash in @_.
     Standard Ext.Direct form fields are removed from argument
     hash; uploaded file(s) will be passed in file_uploads hash
     element. It will only be present when there are uploaded
     files.

   - All Methods are called in scalar context. Returning one
     scalar value is OK; returning array- or hashref is OK too.
     Do not return blessed objects; it is almost always not
     obvious how to serialize them into JSON that is expected by
     client side. Just don't do it.

   - If an error is encountered while processing request, throw
     an exception with die() or croak(). Do not return some
     obscure value that client side is supposed to know about.
 
   - Poll handler methods are called in list context and do not
     receive any arguments. Return values must be instantiated
     Event object(s), see L<RPC::ExtDirect::EventProvider> for
     more detail.

Caveats

In order to keep this module as simple as possible, I had to sacrifice the ability to automatically distinguish inherited class methods. In order to declare inherited class methods as Ext.Direct exportable you have to override them in subclass, like that:

package foo;
use RPC::ExtDirect;

sub foo_sub : ExtDirect(1) {
    my ($class, $arg) = @_;

    # do something
    ...
}

package bar;
use base 'foo';

sub foo_sub : ExtDirect(1) {
    my ($class, $arg) = @_;

    # call inherited method
    return __PACKAGE__->SUPER::foo_sub($arg);
}

sub bar_sub : ExtDirect(2) {
    my ($class, $arg1, $arg2) = @_;

    # do something
    ...
}

On the other hand if you don't like class-based approach, just don't inherit your packages from one another. In any case, declare your Methods explicitly every time and there never will be any doubt about what Method gets called in any given Action.

DEPENDENCIES

RPC::ExtDirect is dependent on the following modules: Carp Attribute::Handlers

BUGS AND LIMITATIONS

Perl versions below 5.6 are not supported.

There are no known bugs in this module. Please report problems to author, patches are welcome.

SEE ALSO

Alternative Ext.Direct Perl implementations: CatalystX::ExtJS::Direct by Moritz Onken, https://github.com/scottp/extjs-direct-perl by Scott Penrose.

For Web server gateway implementations, see CGI::ExtDirect and Plack::Middleware::ExtDirect modules based on RPC::ExtDirect engine.

For configurable Ext.Direct API options, see RPC::ExtDirect::API module.

AUTHOR

Alexander Tokarev <tokarev@cpan.org>

LICENSE AND COPYRIGHT

Copyright (c) 2011 by Alexander Tokarev.

This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See perlartistic.