[Catalyst] Catalyst::Helper::Controller::DBIC::API::SOAP?

Ian Sillitoe ian at sillit.com
Tue May 19 16:22:37 GMT 2009


Hullo all,

Part of a project I've been working on for a while involves providing access
to a whole bunch of data lookup webservices. Part of the specification for
this project is that these services should be made available through SOAP
and have WS-I compliant WSDL documents.

It turns out that since most of the database lookups were essentially
returning sets of rows for a given column (or a single row for a given
primary key) so that's a lot of boilerplate perl and WSDL to manage. In an
attempt to keep myself sane during development/maintenance I resolved to
generate all the boilerplate code (WSDL, controller, live tests, etc)  from
as little configuration as possible. Given that some of the services are
simply primary key lookups, the minimal amount of information could be as
little as the database connection and the desired endpoint (
http://my.server.com/api/soap/dataservices).

To say that this is a little rough round the edges is an understatement, but
I've now got it to a point where it works for me and figured it might save
someone else some time too. I've copied and pasted the usage from this
project below as a first pass to get comments.

Caveats:

 - I've called this DBIC::API::SOAP because that seems to be where it fits
into the grand scheme of things, however it doesn't current use any of
DBIC::API at all (it probably should in the long term, but currently uses
it's own abstract interface - DBIx::Class::WebService)

 - This uses C::C::SOAP::DocumentLiteralWrapped (sorry ruoso!) because
DocLitWrapped happened to make it easier for me to generate and test WS-I
compliant WSDLs required for work. The intention would be to move this
across to a better schema when I've got time.

 - This currently generates a bunch of scaffolding rather than making much
attempt to refactor stuff into runtime (all the clever stuff is done by
C::C::SOAP). This is partly because I'm lazy and was running this on top of
C::C::SOAP where the WSDL is required as a flat file. However, this is also
partly because you wouldn't want to change your external WSDL at runtime
anyway so I didn't think this was too much of a bad thing.

Let me know your thoughts.

Cheers,

Ian


USAGE

The catalyst project "TestApp" in the test directory of this distribution
provides a good usage as it was created from scratch using the
Catalyst::Helper
provided in this distribution.

As always the Catalyst project starts with:

    % catalyst.pl TestApp

At the absolute minimum, the user needs to have a database that contains
tables
with primary keys. If no other config is provided, the helper tool will
automatically define one operation per table corresponding to a simple
primary
key lookup.

First, we create a catalyst DBIC model that will help us interact with our
database:

    % cd TestApp

    % cp /path/to/my/sqlite/database/testws.db .

    % script/testapp_create.pl model TestDB DBIC::Schema TestApp::Schema \
        create=3Ddynamic dbi:SQLite:testws.db

     exists "/path/to/TestApp/script/../lib/TestApp/Model"
     exists "/path/to/TestApp/script/../t"
     exists "/path/to/TestApp/script/../lib/TestApp"
    created "/path/to/TestApp/script/../lib/TestApp/Schema.pm"
    created "/path/to/TestApp/script/../lib/TestApp/Model/TestDB.pm"
    created "/path/to/TestApp/script/../t/model_TestDB.t"

Now, we can feed this model name into the helper tool to generate SOAP-based
webservice from them:

    % script/testapp_create.pl controller API::SOAP::DataServices \
        DBIC::SOAP::DocumentLiteralWrapped TestDB

    # starts up the Catalyst project to resolve the model name into DBIC
Schema

    created "root/static/wsdl"
    created "root/static/wsdl/testapp_controller_api_soap_dataservices.wsdl"
    created "lib/TestApp/Controller/API/SOAP/DataServices.pm"
    created "t/controller_API-SOAP-DataServices.t"

The Path actions that this provides:

    /api/soap/dataservices/wsdl              # returns WSDL as text/xml

    /api/soap/dataservices                   # SOAP endpoint
    /api/soap/dataservices/ArtistByArtistId  # SOAP action handler
    /api/soap/dataservices/CdByCdId          # SOAP action handler

As a side note, you can also use your own configuration file rather than
relying on the default operations (see DBIx::Class::WebService for more
details)

    # my-dataservices.json
    {
        "name":      "DataServices",
        "operations": [
            {
                "name":                 "SearchArtistsByName",
                "data_source_name":     "Artist",
                "input_columns":        "name",
                "search_attributes":    { "rows": "50" },
                "documentation":        "Returns a list of artists matching
a simple text search"
            }
        ]
    }


You should be able to run the test server and point your browser at:

    % script/testapp_server.pl

    http://localhost:3000/api/soap/dataservices/wsdl

To view the automatically generated WSDL

You can also run the generated tests as usual (output has been truncated for
clarity).

    % prove -l

    t/01app...............................ok
    t/02pod...............................skipped: set TEST_POD to enable
this
    t/03podcoverage.......................skipped: set TEST_POD to enable
this
    t/controller_API-SOAP-DataServices....1/10 [debug] Debug messages
enabled

    <snip>

    [debug] Searching CdByCdId (Cd): cd_id=3D1
    [debug] Outgoing XML: <Envelope
xmlns=3D"http://schemas.xmlsoap.org/soap/envelope/"><Body><x0:CdByCdIdRespo=
nse
xmlns:x0=3D"http://localhost:3000/api/soap/dataservices
"><x0:CdByCdIdRecord><x0:
artist_id>1</x0:artist_id><x0:cd_id>1</x0:cd_id><x0:title>Electric
Ladyland</x0:title><x0:year>1999</x0:year></x0:CdByCdIdRecord></x0:
CdByCdIdResponse></Body></Envelope>
    [info] Request took 0.027138s (36.849/s)


.------------------------------------------------------------+-----------.
    | Action                                                     | Time
|

+------------------------------------------------------------+-----------+
    | /api/soap/dataservices/rpc_endpoint                        | 0.014138s
|
    |  -> /api/soap/dataservices/CdByCdId                        | 0.012903s
|
    | /api/soap/dataservices/end                                 | 0.001441s
|

'------------------------------------------------------------+-----------'

    <snip>

    [debug] Searching ArtistByArtistId (Artist): artist_id=3D1
    [debug] Outgoing XML: <Envelope
xmlns=3D"http://schemas.xmlsoap.org/soap/envelope/"><Body><x0:
ArtistByArtistIdResponse
xmlns:x0=3D"http://localhost:3000/api/soap/dataservices"><x0:
ArtistByArtistIdRecord><x0:artist_id>1</x0:artist_id><x0:name>Jimi
Hendrix</x0:name></x0:ArtistByArtistIdRecord></x0:ArtistByArtistIdResponse>=
</
Body></Envelope>
    [info] Request took 0.022939s (43.594/s)

.------------------------------------------------------------+-----------.
    | Action                                                     | Time
|

+------------------------------------------------------------+-----------+
    | /api/soap/dataservices/rpc_endpoint                        | 0.012840s
|
    |  -> /api/soap/dataservices/ArtistByArtistId                | 0.011673s
|
    | /api/soap/dataservices/end                                 | 0.001229s
|

'------------------------------------------------------------+-----------'

    t/controller_API-SOAP-DataServices....ok
    t/model_TestDB........................ok
    All tests successful.
    Files=3D5, Tests=3D13,  7 wallclock secs ( 0.07 usr  0.02 sys +  6.32 c=
usr
0.61
csys =3D  7.02 CPU)
    Result: PASS


-- =

Ian Sillitoe
CATH Team -- http://cathdb.info





-- =

Ian Sillitoe
CATH Team -- http://cathdb.info
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20090519/1c9d4=
f93/attachment.htm


More information about the Catalyst mailing list