Gantry::Plugins::SOAP::RPC(3)

NAME
Gantry::Plugins::SOAP::RPC - RPC style SOAP support

SYNOPSIS
In your GEN module:

    use Your::App::BaseModule qw( -PluginNamespace=YourApp SOAP::RPC );
    # this will export these into your package:
    #    soap_in
    #    soap_out
    #    do_main
    #    do_wsdl
    #    return_error

    sub get_soap_ops {
        my $self = shift;

        return {
            soap_name      => 'Kids',
            location       => $self->location,
            namespace_base => 'localhost',
            operations     => [
                {
                    name => 'get_count',
                    expects => [
                        { name => 'table_name', type => 'xsd:string' },
                    ],
                    returns => [
                        { name => 'count', type => 'xsd:int' },
                    ],
                },
            ],
        };

    }

Add as many operations as you need.

In your stub:

    use Your::GEN::Module;

    sub get_count {
        my $self = shift;
        my $data = shift;

        return { ... };
    }

Your data will have whatever was in your client's soap request. You are responsible for diagnosing all errors and for returning the correct structure (it should match the returns list). But feel free to just die when you spot an error, this module traps those and uses its "return_error" method which sends valid SOAP fault messages.

DESCRIPTION
This plugin is for rpc style SOAP requests only. If you need document style requests, you should use Gantry::Plugins::SOAP::Doc.

Bigtop can help a lot with the use of this plugin. Below is what you need to do manually, should you choose that route. But first, I'll explain what is happening from overhead.

For each SOAP handler in your app, there should be one controller (or a stub/GEN controller pair) placed on a location in your httpd conf. If you do the normal thing, the GEN module (or controller if you don't have a GEN) uses this module and accepts all the exports (the list is mainly for documentation, since all of them are exported by default).

Two of the exports are Gantry handlers: "do_main" and "do_wsdl". This means that the caller will look for the service itself at the location from httpd.conf, while they will add /wsdl to get the WSDL file. For example, suppose you have this in your httpd.conf:

    <Location /appname/SOAP>
        SetHandler  perl-script
        PerlHandler YourApp::YourSoapStub
    </Location>

Then users will hit "/appname/SOAP" to get the service and "/appname/SOAP/wsdl" to get the WSDL file.

This module registers a "pre_init" callback which steals all of the body of the POST from the client. Then it lets Gantry do its normal work. So your stub methods will be called through a site object.

All SOAP requests are handled by "do_main", which this module exports. It uses the internal "soap_in" method to parse the input. You must import "soap_in", so it will be in the site object. It fishes the client's desired action out of the incoming SOAP request and calls the method of the same name in the stub module. That method receives the SOAP request as parsed by XML::Simple's "XMLin" function. It must return the structure which will be returned to the client.

The action method's structure is then fed to "soap_out" (which you must also import) and the result is returned as a plain text/xml SOAP message to the client. "SOAP::Lite"'s "SOAP::Data" and "SOAP::Serializer" are used to the hard work of making output.

Here are the details of what your need to implement.

You need a "namespace" method which returns the same name as the "-PluginNamespace".

You also need a "get_soap_ops" method which returns a hash describing your WSDL file. See the SYNOPSIS for an example. Here's what the keys do:

soap_name
    This is used whenever SOAP requires a name. Prefixes and suffices are appended to it, as in NAME_Binding.

location
    Normally, you should make this "<$self-"location>>, so that all requests come to the same SOAP controller which produced the WSDL file.

namespace_base
    This should be everything after "http://" and before "<$self-"app_rootp>> in the URL of the SOAP service. Usually that is just the domain.

operations
    An array reference of hashes describing the services you offer. Each element is a hash with these keys:

    name
        The name of the action method in your stub controller, which will handle the request.

    expects
        An array reference of parameters the method expects. These have two keys: name and type. They type can be any valid xsd: type or any other type in your WSDL file. If you need to define types, see WSDL TYPES below.

    returns
        An array exactly like expects, except that it represents your promise to the client of what will be in the SOAP response.

get_callbacks
    Called by Gantry's import method to register the callbacks for this module.

WSDL TYPES
Gantry ships with wsdl.tt which it uses by default to construct the WSDL file from the result of "get_soap_ops". If you need to define types, simply copy that template into your own root path and add the types you need. If you want to supply your own data to the template, just implement your own "get_soap_ops" and return whatever your template expects.

METHODS
All of these are exported by default. You may supply your own, or accept the imports. Failure to do one of those two is fatal. Doing both will earn you a subroutine redefinition warning.

steal_post_body
    Steals the body of the POST request before Gantry's engine can get to it. This method must be registered to work. Do that by using the plugin as you use your base module:

        use Your::App qw(
            -PluginNamespace=module_name
            SOAP::RPC
        );

    Note that you don't have to do this in the same place as you load the engine. In fact, that probably isn't a great idea, since it could lead you down the primrose path to all of your modules using the plugin's "steal_post_body", leaving you without form data.

    Then, you must also implement a method called "namespace" which returns the same string as the "-PluginNamespace".

    This method delegates its work to "consume_post_body", which is exported by each engine.

do_main
    The SOAP service. Fishes the POST body with "get_post_body" parses it using "soap_in", dispatches to your action method, makes the SOAP response with "soap_out", and returns it.

do_wsdl
    Uses wsdl.tt to return a WSDL file for your service to the client. It uses "get_soap_ops" to know what to put in the WSDL file. Its template is wsdl.tt. You must call yours that, but feel free to copy the standard one to an earlier element of the root template path and edit it.

soap_in
    For internal use. Uses XML::Simple to parse the incoming SOAP request.

soap_out
    For internal use. Forms a valid (though simple) SOAP response. Note that this module may not be able to handle your complex types. It uses "SOAP::Lite"'s "SOAP::Data" and "SOAP::Serializer" modules to generate the XML response.

return_error
    Returns a valid SOAP fault response. You must either accept this method in your imports or write one yourself. The standard error is not SOAP aware.

AUTHOR
Phil Crow, <crow.phil@gmail.com>

COPYRIGHT and LICENSE
Copyright (c) 2007, Phil Crow

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.6 or, at your option, any later version of Perl 5 you may have available.