=pod =begin readme text RPC::ExtDirect ============== =end readme =for readme stop =head1 NAME RPC::ExtDirect - Easily integrate Perl server code with JavaScript apps =head1 SYNOPSIS package Foo::Bar; use RPC::ExtDirect Action => 'FooBar'; sub sum : ExtDirect( len => 2 ) { my ($class, $a, $b) = @_; return $a + $b; } sub login : ExtDirect( params => [qw/ user pass /] ) { my ($class, %arg) = @_; if ( $arg{user} eq 'foo' && $arg{pass} eq 'bar' ) { return { success => \1, # JSON::true }; } else { return { success => \0, # JSON::false error => "You shall not pass!" }; } } =head1 DESCRIPTION =for readme continue RPC::ExtDirect suite of modules provides an easy, simple and robust way to write Perl server side code that could be used with HTML5 Rich Internet Applications based on JavaScript frameworks L<Ext JS|http://www.sencha.com/products/extjs/> and L<Sencha Touch|http://www.sencha.com/products/touch/>. The suite consists of the core RPC::ExtDirect module that implements Ext.Direct protocol and transport layer, several server environment-specific peripheral gateways, a standalone pure Perl server, two Perl clients, and even its own specialized testing scaffold! We've got it covered front to back. :) =for readme stop =head1 INTRODUCTION AND EXAMPLES If you are not familiar with Ext.Direct, start with L<RPC::ExtDirect::Intro> for more explanations and a few examples, both easy and more advanced. =head1 WHEN TO USE IT, AND WHY Ext.Direct is a Remote Procedure Call (RPC) protocol provided out of the box with JavaScript frameworks by L<Sencha|http://www.sencha.com>. It is deeply integrated in the data services, and is supported by a slew of components. Besides that, Ext.Direct also has several major advantages over similar protocols like XML-RPC and JSON-RPC: =over 4 =item * Built in service discovery mechanism: server side API is published to the client via GET requests to a preconfigured URI =item * Dead simple client side invocation via functional stubs created from the API declaration =item * Support for request batching with configurable timeout =item * Easy file uploads via form submits, with all the complexity handled behind the curtains by the framework and the server side stack =item * Asynchronous push notifications via event polling =back All this makes Ext.Direct a no-brainer when developing Web apps with Ext JS or Sencha Touch. And with RPC::ExtDirect, choosing Perl to write server side code for Web apps comes naturally, too. :) =for readme stop =head1 HOW TO USE Since Ext.Direct is just a transport layer, you don't need to change your app architecture to work around it. If you have an existing server side API you can publish it with minimal effort; if you're starting from scratch, add the classes and methods as you go. Note that with Ext.Direct, we're talking about classes and methods - that owes to the fact that Ext.Direct originated in Ext JS framework, which itself is written in JavaScript with object-oriented approach in mind. This does not mean you can't go functional or even procedural with RPC::ExtDirect; it is perfectly possible to cook your own flavor of spaghetti code under the light OOP sauce that RPC::ExtDirect provides. In order for a method to be published to the outside world, it needs to be declared in the L<Ext.Direct API|RPC::ExtDirect::Intro/API>. As of version 3.0, it can be done in two ways: either with C<ExtDirect> attribute as shown in the L</SYNOPSIS>, or by including the method in a hashref fed to L<RPC::ExtDirect::API> constructor. See L<RPC::ExtDirect::API/"COMPILE VS RUN TIME DEFINITION"> for more detail. =head1 METHODS AND CALLING CONVENTIONS Unlike Ext.Direct specification (and reference PHP implementation, too) RPC::ExtDirect does not impose strict architectural notation on server side code. There is no mandatory object instantiation and no assumption about the code called. That said, an RPC::ExtDirect Method should conform to the following conventions: =over 4 =item * Be a class method, i.e. be aware that its first argument will be the package (class) name. Just ignore it if you don't want it. =item * Ordered (numbered) arguments are passed as list in C<@_>, so C<$_[1]> is the first argument. No more than number of arguments declared in the L<Method|RPC::ExtDirect::Intro/Method> definition will be passed to the Method; any extra will be dropped silently. Less arguments than declared will result in an L<Exception|RPC::ExtDirect::Intro/Exception> returned to the client side, and Method never gets called. =item * Named arguments are passed as a hash in C<@_>. No arguments other than declared will be passed to the L<Method|RPC::ExtDirect::Intro/Method>; extra arguments will be dropped silently. If not all arguments are present for the remoting invocation, an L<Exception|RPC::ExtDirect::Intro/Exception> will be returned and the Method never gets called. Starting with Ext JS 4.2.2, it is possble to relax the argument checking requirements; see L<RPC::ExtDirect::API/"Lazy parameter checking"> for more information. =item * Form handlers are passed their arguments as a hash in C<@_>. Standard Ext.Direct form field values are removed from the argument hash; uploaded file(s) will be passed in the C<file_uploads> hash element. It will only be present when there are uploaded files. For more info, see L</"FILE UPLOADS">. Note that any field values in a submitted form will be JSON encoded by the client side. =item * All remoting 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 the client side. JSON encoder will choke and an L<Exception|RPC::ExtDirect::Intro/Exception> will be returned to the client. Having said that, if you know what you are doing, it is possible to adjust the Serializer's behavior with L<RPC::ExtDirect::Config/json_options> Config option. =item * If an error is encountered while processing request, throw an exception: C<die "My error string\n">. Note that C<"\n"> at the end of error string; if you don't add it, C<die()> will append file name and line number to the error message which is probably not the best idea for errors that are not shown in server console but rather passed on to the JavaScript client. RPC::ExtDirect will trim that last C<"\n"> for you before sending the L<Exception|RPC::ExtDirect::Intro/Exception> back to the client side. =item * Poll handler methods are called in list context and do not receive any arguments except an environment object. Return value must be a list of instantiated L<Event|RPC::ExtDirect::Intro/Event> objects, see L<RPC::ExtDirect::Event> for more detail. =back =head1 HOOKS Hooks provide an option to intercept method calls and modify arguments passed to the methods, or cancel their execution. Hooks are intended to be used as a shim between task-oriented Methods and Web specifics. Methods should not, to the reasonable extent, be aware of their environment or care about it; Hooks are expected to know how to deal with Web intricacies but not be task oriented. The best uses for Hooks are: application or package-wide pre-call setup, user authorization, logging, cleanup, testing, etc. Or you can think of the Hooks as poor man's method wrappers without L<Moose's|Moose> power (and associated costs). See more in L<RPC::ExtDirect::API::Hook>. =head1 ENVIRONMENT OBJECTS Since Hooks, and sometimes Methods too, need to be aware of their Web environment, it is necessary to give them access to it in some way without locking in on platform specifics. RPC::ExtDirect's answer to this problem is environment objects. An environment object provides platform-agnostic interface for accessing HTTP headers, cookies, form field values, etc. Such object is guaranteed to have the same set of methods that behave the same way across all platforms supported by RPC::ExtDirect, avoiding portability issues. The interface is modeled after the de facto standard CGI.pm: =over 4 =item * C<$value = $env-E<gt>param('name')> will retrieve a parameter by name =item * C<@list = $env-E<gt>param()> will get the list of available parameters =item * C<$cookie = $env-E<gt>cookie('name')> will retrieve a cookie =item * C<@cookies = $env-E<gt>cookie()> will return the list of cookies =item * C<$header = $env-E<gt>http('name')> will return an HTTP header =item * C<@headers = $env-E<gt>http()> will return the list of HTTP headers =back Of course it is possible to use environment object in a more sophisticated way if you like to, however do not rely on it having a well-known class name as it is not guaranteed. Environment objects are simple helpers held together by duck type. Starting with RPC::ExtDirect 3.0, only L<Hooks|/HOOKS> will receive an environment object by default. For Methods to receive them as well, you need to specify a L<RPC::ExtDirect::API::Method/env_arg> parameter in Method definition. =head1 FILE UPLOADS Ext.Direct offers native support for file uploading by using temporary HTML forms. RPC::ExtDirect supports this feature; upload requests can be processed in a L<Form Handler Method|RPC::ExtDirect::Intro/"Form Handler Method">. The interface aims to be platform agnostic and will try to do its best to provide the same results in all HTTP environments supported by RPC::ExtDirect. In a Form Handler Method, arguments are passed as a hash. If one or more file uploads were associated with request, the argument hash will contain a key with value set to arrayref of file hashrefs. The default name for this key is C<file_uploads>; this can be configured using L<upload_arg|RPC::ExtDirect::API::Method/upload_arg> Method parameter. Each file hashref will have the following keys: =over 4 =item C<type> MIME type of the file, if provided =item C<size> File size, in octets =item C<path> Path to a temporary file that holds uploaded content =item C<handle> Open IO::Handle for the temporary file =item C<basename> Name portion of the originally submitted file name, if provided by the client side =item C<filename> Full original path as sent by the client, if any =back All files passed to a Method need to be processed in that Method; existence of temporary files is not guaranteed after Method returns. =head1 GATEWAYS In RPC::ExtDirect parlance, a Gateway is a module that deals with the specifics of a particular Web server environment. At the time of writing this documentation, the following gateways are available for RPC::ExtDirect: =over 4 =item CGI gateway L<CGI::ExtDirect> is used with the ole goode L<CGI> environment; it is also compatible with the newer L<CGI::Simple> module that is a drop-in replacement for C<CGI.pm>. This gateway is most often used for testing Ext.Direct interfaces, usually with L<Test::ExtDirect> helper module. However, CGI environment is easy to use and set up practically anywhere, and it can be used in the variety of situations where a full blown Perl application server is not feasible. One example of such usage would be retrofitting a legacy system with a modern HTML5 Web interface. =item Plack gateway L<Plack::Middleware::ExtDirect> implements an RPC::ExtDirect interface for L<Plack> application server environment. This gateway should also be used instead of the L<Apache gateway|/"Apache gateway"> in L<mod_perl> environment. =item AnyEvent::HTTPD gateway L<AnyEvent::HTTPD::ExtDirect> implements a completely asynchronous interface for RPC::ExtDirect, based on L<AnyEvent::HTTPD> module. =item Apache gateway L<Apache::ExtDirect> is a legacy gateway for Apache/L<mod_perl> environment. Since it was written, Apache has fallen out of usage with the author and so the gateway is mostly unsupported. You can use L<Plack gateway|/"Plack gateway"> instead, with one of the built in Apache/Plack handlers. =back =head1 MIGRATING FROM PREVIOUS VERSIONS If you are using less than current RPC::ExtDirect version, please refer to L<RPC::ExtDirect::Migration> document for the notes and explanations that might prove useful for migration. =begin readme =head1 INSTALLATION To install this module type the following: perl Makefile.PL make && make test make install =end readme =for readme continue =head1 DEPENDENCIES RPC::ExtDirect is dependent on the following modules: L<Attribute::Handlers>, L<JSON>. The oldest Perl version RPC::ExtDirect is routinely tested against is 5.6.2. =for readme stop =head1 BUGS AND LIMITATIONS At this time there are no known bugs in this module. Please report problems to the author, patches are always welcome. Use L<Github tracker|https://github.com/nohuhu/RPC-ExtDirect/issues> to open bug reports, this is the easiest and quickest way to get your issue fixed. =head1 SEE ALSO Take a look at these useful modules that are a part of RPC::ExtDirect family: =over 4 =item * L<RPC::ExtDirect::Server> - a prebuilt Ext.Direct server in Perl, based on L<HTTP::Server::Simple>. =item * L<RPC::ExtDirect::Client> - a synchronous Ext.Direct client in Perl. =item * L<RPC::ExtDirect::Client::Async> - a fully asynchronous Ext.Direct client in Perl, with API compatible to L<RPC::ExtDirect::Client>. =item * L<Test::ExtDirect> - a set of helper subroutines that make unit testing Ext.Direct APIs a breeze. =back Also you can find additional information in the following Web site links: =over 4 =item * L<Ext JS product website|http://www.sencha.com/products/extjs/> =item * L<Sencha Touch product website|http://www.sencha.com/products/touch/> =item * L<Ext.Direct specification|http://www.sencha.com/products/extjs/extdirect/> =item * L<Ext.Direct support forum|http://www.sencha.com/forum/forumdisplay.php?47> =item * L<Ext.Direct plugin for jQuery|https://github.com/ha-sash/jquery-ext-direct-client> =back =head1 ACKNOWLEDGEMENTS I would like to thank IntelliSurvey, Inc for sponsoring my work on versions 2.x and 3.x of the RPC::ExtDirect suite of modules. =for readme continue =head1 LICENSE AND COPYRIGHT Copyright (c) 2011-2014 by Alex Tokarev E<lt>tokarev@cpan.orgE<gt>. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See L<"perlartistic">. =cut