NAME

RPC::ExtDirect - Easily integrate Perl server code with JavaScript apps

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 => ['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!"
        };
    }
}

DESCRIPTION

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 Ext JS and Sencha 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. :)

INTRODUCTION AND EXAMPLES

If you are not familiar with Ext.Direct, start with RPC::ExtDirect::Intro for more explanations and a few examples, both easy and more advanced.

WHEN TO USE IT, AND WHY

Ext.Direct is a Remote Procedure Call (RPC) protocol provided out of the box with JavaScript frameworks by Sencha. 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:

  • Built in service discovery mechanism: server side API is published to the client via GET requests to a preconfigured URI

  • Dead simple client side invocation via functional stubs created from the API declaration

  • Support for call metadata that is handled separately from the arguments for method invocation

  • Support for request batching with configurable timeout

  • Easy file uploads via form submits, with all the complexity handled behind the curtains by the framework and the server side stack

  • Asynchronous push notifications via event polling

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. :)

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 Ext.Direct API. As of version 3.0, it can be done in two ways: either with ExtDirect attribute as shown in the "SYNOPSIS", or by including the method in a hashref fed to RPC::ExtDirect::API constructor. See "COMPILE VS RUN TIME DEFINITION" in RPC::ExtDirect::API for more detail.

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:

  • 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.

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

  • Named arguments are passed as a hash in @_. No arguments other than declared will be passed to the Method; extra arguments will be dropped silently. If not all arguments are present for the remoting invocation, an 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 "Lazy parameter checking" in RPC::ExtDirect::API for more information.

  • Form handlers are passed their arguments as a hash in @_. Standard Ext.Direct form field values are removed from the argument hash; uploaded file(s) will be passed in the file_uploads hash element. It will only be present when there are uploaded files. For more info, see "FILE UPLOADS".

    Note that any field values in a submitted form will be JSON encoded by the client side.

  • 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 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 "json_options" in RPC::ExtDirect::Config Config option.

  • If an error is encountered while processing request, throw an exception: die "My error string\n". Note that "\n" at the end of error string; if you don't add it, 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 "\n" for you before sending the Exception back to the client side.

  • Poll handler methods are called in list context and do not receive any arguments except the environment object. Return value must be a list of instantiated Event objects, see RPC::ExtDirect::Event for more detail.

CALL METADATA

Imagine a Web application with an editable Grid populated with data from a database table. To update the database when changes are saved, the client will send an array of changed records that will be passed to the corresponding Ext.Direct Method as call arguments. But what about the table name?

The usual approach is to create a separate set of 4 CRUD methods (Create, Read, Update, Delete) for each table, and expose these methods as a separate Action. While tried and true, this approach leads to bloated Ext.Direct API when there are many tables, with lots of packages and code duplication just for the sake of editing a database table. This can be especially frustrating when the application has many similar tables differing only in the name.

Call metadata allows solving this and many other problems by passing some information to the called Method along with the main data but not as a part of the arguments. In particular, using metadata allows for having one set of CRUD methods for all similar data tables and send different table name for each call as metadata.

More of it, Ext JS (and RPC::ExtDirect, too) allow having different calling convention for Method arguments and metadata, e.g. having a Named Method with ordered (by position) metadata, and vice versa.

Call metadata is a new feature in Ext JS 5.1+.

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 Moose's power (and associated costs).

See more in RPC::ExtDirect::API::Hook.

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:

  • $value = $env->param('name') will retrieve a parameter by name

  • @list = $env->param() will get the list of available parameters

  • $cookie = $env->cookie('name') will retrieve a cookie

  • @cookies = $env->cookie() will return the list of cookies

  • $header = $env->http('name') will return an HTTP header

  • @headers = $env->http() will return the list of HTTP headers

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 Hooks will receive an environment object by default. For Methods to receive them as well, you need to specify a "env_arg" in RPC::ExtDirect::API::Method parameter in Method definition.

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 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 file_uploads; this can be configured using upload_arg Method parameter.

Each file hashref will have the following keys:

type

MIME type of the file, if provided

size

File size, in octets

path

Path to a temporary file that holds uploaded content

handle

Open IO::Handle for the temporary file

basename

Name portion of the originally submitted file name, if provided by the client side

filename

Full original path as sent by the client, if any

All files passed to a Method need to be processed in that Method; existence of temporary files is not guaranteed after Method returns.

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:

CGI gateway

CGI::ExtDirect is used with the ole goode CGI environment; it is also compatible with the newer CGI::Simple module that is a drop-in replacement for CGI.pm.

This gateway is most often used for testing Ext.Direct interfaces, usually with 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.

Plack gateway

Plack::Middleware::ExtDirect implements an RPC::ExtDirect interface for Plack application server environment. This gateway should also be used instead of the Apache gateway in mod_perl environment.

AnyEvent::HTTPD gateway

AnyEvent::HTTPD::ExtDirect implements a completely asynchronous interface for RPC::ExtDirect, based on AnyEvent::HTTPD module.

Apache gateway

Apache::ExtDirect is a legacy gateway for Apache/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 Plack gateway instead, with one of the built in Apache/Plack handlers.

MIGRATING FROM PREVIOUS VERSIONS

If you are using less than current RPC::ExtDirect version, please refer to RPC::ExtDirect::Migration document for the notes and explanations that might prove useful for migration.

DEPENDENCIES

RPC::ExtDirect is dependent on the following modules: Attribute::Handlers, JSON.

The oldest Perl version RPC::ExtDirect is routinely tested against is 5.6.2.

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 Github tracker to open bug reports, this is the easiest and quickest way to get your issue fixed.

SEE ALSO

Take a look at these useful modules that are a part of RPC::ExtDirect family:

Also you can find additional information in the following Web site links:

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.

LICENSE AND COPYRIGHT

Copyright (c) 2011-2016 by Alex Tokarev <tokarev@cpan.org>.

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