|
NAMERPC::ExtDirect::API - Ext.Direct service discovery handlerSYNOPSISuse RPC::ExtDirect::Config; use RPC::ExtDirect::API; my $config = RPC::ExtDirect::Config->new( namespace => 'MyApp', router_path => '/router', poll_path => '/events', remoting_var => 'MyApp.REMOTING_API', polling_var => 'MyApp.POLLING_API', ); my $api = RPC::ExtDirect::API->new_from_hashref( config => $config, api_href => { before => 'MyApp::Util::global_before_hook', after => 'MyApp::Util::global_after_hook', 'MyApp::Server::Foo' => { before => 'MyApp::Server::Foo::package_before_hook', action => 'MyApp.Server.Foo', # JavaScript style with dots methods => { foo => { len => 1, }, bar => { params => ['foo', 'bar'], }, baz => { params => ['frobbe', 'throbbe'], metadata => { params => ['mymse', 'qux'], } } } } } ); DESCRIPTIONWith Ext.Direct, the API exposed by the server side is published to the clients via fixed URI, a GET request to which produces a response with a piece of JavaScript code containing the API declaration. This module handles the API service discovery requests.The Ext.Direct API declaration is in fact a tree-like data structure (an Object in JavaScript parlance) containing description of Actions and Methods available to the client. This data structure is encoded in JavaScript code statement that is regenerated dynamically every time it is requested. No caching is used at this time. ACTIONS AND METHODSAn Action in Ext.Direct parlance is a collection of Method definitions. The nearest similar Perl thing is a package, other languages may call it a Class. In RPC::ExtDirect, an Action needs a unique name that can be nested; Methods should have unique names within their Actions.Action namesIf the Action name is not specified explicitly, it will be deduced from the package name. If api_full_action_names Config option is truthy, Action name will be similar to the package name with the same level of nesting, having '::' replaced with dots: 'Foo::Bar::Baz' -> 'Foo.Bar.Baz'. Starting with Ext JS version 4.2.1, this allows having nested API objects on the client side as well, so you can call the server side methods like normal JavaScript methods:Foo.Bar.Baz.do_foo(...); However nested API objects are not supported in Ext JS below 4.2.1 as well as in Sencha Touch 2.x, so the default behavior is to use only the last chunk of the package name: 'Foo::Bar::Baz' -> 'Baz'. Method calling conventionsExt.Direct specification defines four calling convention for methods:
When an Ext.Direct remoting method is called on the client side, the transport layer will perform a check on the actual arguments passed to the method stub, and throw an exception if arguments do not conform to the API declaration. To declare an ordered method, define the "len" option with the number of parameters accepted; this number may be 0 for methods that do not accept any parameters at all. To declare a named method, define the "params" option with the names of mandatory parameters. It is worth noting that only existence of parameters is mandatory; their values may as well be undefined. If not all arguments exist, an exception will be thrown. If there are any extra arguments not declared for this method, an exception will be thrown as well, unless strict argument checking is turned off (see below). It is also possible to declare a named Method with no mandatory parameters at all; do that by setting "params" option to an empty arrayref: "[]". In that case, the calling convention is still honored but all parameters are treated as optional and no checks are performed. Lazy parameter checkingStarting with Ext JS 4.2.2 and RPC::ExtDirect 3.00, it is possible to perform less strict parameter checking on by-name methods. All parameters explicitly declared for a method will still be treated as mandatory, but no exception will be thrown if undeclared arguments are passed into the method stub; these "extra" arguments will be transmitted to the server side and passed into the actual Method. It is also possible to completely bypass the argument checking by not declaring any mandatory methods for a Method.As mentioned above, the strict checking is enabled by default; to disable it, set the strict option to falsy value for any given method. Lazy parameter checking is not supported in Ext JS below 4.2.2, and in Sencha Touch 2.x. Call metadataStarting with Ext JS 5.1.0 and RPC::ExtDirect 3.20, it is possible to pass additional set of metadata arguments to any Method that supports it.Metadata arguments can differ in calling convention from the main arguments; e.g. it is possible to have an Ordered method with named metadata, and vice versa. The only kind of Methods unable to receive metadata is Poll handlers. Call metadata is optional and will only be passed to the Methods that declare their metadata convention. Unlike the main arguments, call metadata is always passed by reference, in arrayref or hashref. In order to support call metadata, the Method declaration should include corresponding parameters via the "metadata" keyword. Note that for Ordered Methods, metadata declaration should always include the position for the metadata argument. COMPILE VS RUN TIME DEFINITIONThere are two ways to define Ext.Direct API with RPC::ExtDirect: statically by using "ExtDirect" subroutine attribute, or dynamically by including Actions and Methods in a hashref that is used to configure an API object.Both of these ways have their advantages and disadvantages. Using the "ExtDirect" attribute, it's easier to keep definitions closer to the actual code so that when the code changes, its definition can be remembered to be changed as well. Also this approach is very easy to use and start with; just add the attribute to your code, and you're good to go. Also, the attribute syntax is expressive enough to be self-documenting, so often no other API documentation is needed. On the other hand, for larger and more centralized projects it may be easier to keep all API definitions in one place rather than spread over dozens of packages. Besides easier maintenance, using dynamic approach allows having more than one active API object at a given time, possibly implementing different APIs tailored for usage patterns of a particular application. Note that these two methods are not mutually exclusive, but it is not recommended to mix them unless you are ready to deal with ensuing timing issues. You've been warned. DEFINING METHODS STATICALLYIn order to add a subroutine to the Ext.Direct interface, use an attribute with the sub definition:sub foo : ExtDirect(...) {} Note that there can be no space between the "ExtDirect" attribute name and the opening parens; also in Perls older than 5.12, the attribute statement cannot span multiple lines, i.e. the whole "ExtDirect(...)" construct should fit in one line. This is due to limitations in Perl code parser. Inside the parentheses, one of the following mutually exclusive option keywords is mandatory:
Having more than one calling convention keyword in the Method definition is not supported and will lead to undefined behavior. Besides the mandatory calling convention keyword, there are optional Method attributes in hash-like "key => value" form. See more in "new" in RPC::ExtDirect::API::Method. DEFINING METHODS DYNAMICALLYIf you find the static definition method inconvenient or hard to maintain, use dynamic definition instead. You can create a new API object using new_from_hashref constructor, or just init the global API instance from a hashref containing the API definition:my $api = RPC::ExtDirect->get_api(); $api->init_from_hashref({ 'MyApp::Server::Foo' => { methods => { ordered_method => { len => 1, }, named_method => { params => [qw/ foo bar /], strict => !1, }, form_handler => { formHandler => 1, }, poll_handler => { pollHandler => 1, }, }, }, }); Keywords and options are mostly the same as with the static definition; refer to "new" in RPC::ExtDirect::API::Method for details. GLOBAL API TREE INSTANCEUnder the hood, static API definition operates on a global instance of "RPC::ExtDirect::API", created at the package compilation time and available globally throughout the application.Versions 1.x and 2.x of RPC::ExtDirect used package global variables to hold this information; version 3.0 is using a global RPC::ExtDirect::API object instead. This object is held in a private variable and can be retrieved by the get_api method: my $global_api = RPC::ExtDirect->get_api; This API object holds an instance of RPC::ExtDirect::Config with a set of options used to configure the API object behavior. This Config instance can be retrieved to set options directly: my $cfg = RPC::ExtDirect->get_api->config; $cfg->option1('foo'); $cfg->option2('bar'); Since the API object is a normal object, and the config method is a normal accessor, it is possible to replace that Config instance with a new one. However this may result in a loss of statically defined Config options, and is not recommended. Instead, use import package sub to configure the global API when using static API definitions. The global API instance is used by default to generate the API declaration requested by the client side, and for dispatching remoting calls from the client side. If you prefer more control over the API tree, create the API object explicitly as shown in the SYNOPSIS, and pass it to the gateway object. Refer to the actual gateway documentation for details. Because attribute parsing happens at package compilation time, it is hard to predict the order in which the methods will be processed. To provide some help with debugging, RPC::ExtDirect will throw an error if you are trying to redefine a Method; usually that means a mistake has been made somewhere. API CONFIGURATIONRPC::ExtDirect::API provides two ways to configure Ext.Direct API declaration variables to accommodate for specific application needs: dynamic via an RPC::ExtDirect::Config instance, and static via "import" package subroutine.An example of the new dynamic configuration is available in the "SYNOPSIS" above. This is the preferred way of configuring the API in large complex applications; it allows keeping the whole API definition in one place instead of distributed among the packages. It is also possible to define more than one API this way, for publishing to different clients. The static configuration has been available since version 1.0 and will be supported going forward. This way it is possible to configure the API variables at compile time: use RPC::ExtDirect::API namespace => 'myApp', router_path => '/router', poll_path => '/events', remoting_var => 'Ext.app.REMOTING_API', polling_var => 'Ext.app.POLLING_API', auto_connect => 0, no_polling => 0, before => \&global_before_hook, after => \&global_after_hook, ; Under the hood, the above code will set specified options on the Config instance held in the global API object. API CONFIGURATION OPTIONSThe following configuration options are supported by RPC::ExtDirect::API:
API OBJECT INTERFACERPC::ExtDirect::API provides several public methods:
ACCESSOR METHODSFor RPC::ExtDirect::API, the following accesor methods are provided:
SEE ALSOMore information on the configuration options can be found in RPC::ExtDirect::Config documentation.
Visit the GSP FreeBSD Man Page Interface. |