http://qs321.pair.com?node_id=624197

Cagao has asked for the wisdom of the Perl Monks concerning the following question:

I have my own module that requests are dispatched to as you'd expect.

When the module is loaded/used, i assume it is in OO context since the first argument is the name of the module/class. So, should I create a new() sub? is it required? is it called quietly if it does exist before calling the actual function/method requested by the SOAP call?

At the minute I'm bless'ing $self={} with the $class that is passed in first, but at the beginning of each sub in the module.

What's "best practice" in this situation? Create another 'private' sub to do the bless'ing and basic validation? etc.

And finally, if i wanted my SOAP service using mod_perl or Fast-CGI, should i 'use' all required modules in the calling script to ensure everything is loaded up first? or does SOAP::Lite take care of this for me?

Replies are listed 'Best First'.
Re: SOAP Modules (OO or not?)
by jhourcle (Prior) on Jun 30, 2007 at 12:59 UTC

    It's called the "Simple Object Access Protocol", and it's basically exposing method calls, but it's typically implemented over stateless protocols (eg, HTTP). Therefore, if you're going to be creating new objects, you'll need to deal with maintaining state and ensuring that the objects are available from call to call. (because in the case of mod_perl, you're running under Apache, a forking server, so you'd want the same object available to each webserver child).

    If I needed to do something like this, I'd probably have to go with a lightweight object, registered in a database. If they're small objects, you might be able to have the client pass them with each method call. (see Objects Access in the SOAP::Lite guide)

    As for what you need in the code for the service -- 'use SOAP::Lite' is for the SOAP client. You'll want to use the appropriate SOAP::Transport class for your implementation.

      Maybe I didn't explain too well, consider this plain module I use for handling SOAP requests...
      package SOAPServer; use strict; use warnings; sub myfunction { my $class = shift; my $self = {}; bless ($self, $class); my $one = shift; my $two = shift; $self->{one} = $one; $self->{two} = $two; return $self; } 1;
      Is that okay on it's own, or should I create a new() sub to do the bless'ing? I'm sure it's more a question of "best practice" than anything else.

      I'm just thinking that I'll soon have lots of sub's in the one module, so it'd obviously make sense to move the bless'ing stuff into a seperate private sub.

      In the future one sub may indeed call other local subs, so if nothing else, blessing it to the class would make my code nicer to read with $self->fun2(), and let me structure the object nicely, and pass the whole thing back to the calling SOAP client.

      Thoughts?

        So, if someone wanted to call the same method twice on the same object, you've managed to completely remove that ability.

        I guess you could do something like:

        sub myfunction { my $self = get_object( shift ); ... # whatever's function specific, and not related to # creation of the object } sub get_object { my $self = shift; if ( !ref $self ) { return $self->new() } # a string? if ( UNIVERSAL::isa( $self, __PACKAGE__ ) { return $self } return __PACKAGE__->new(); } sub new { ... }

        But, it doesn't seem like a very clean interface to me ... I mean, how can we tell what arguments should've been part of the object initialization, and what were arguments to the method call?

        Personally, I'm a user of SOAP::Lite, but I have a feeling that its history, having been created when SOAP was basically just a thin wrapper around XML RPC, was a problem, as almost all of the examples you find are these sorts of calls. I don't know that there is a good 'best practice' in how to deal with passing objects using SOAP::Lite. (if there is, I'd love to know about it myself)

        Since nobody else is saying anything, I'll just give my thoughts, which are as follows: WTF?!? You're instantiating an object of this class when calling some random method, like a method of the SOAP-exposed API? No, that's not good at all.

        BTW, if you're looking for a role model distribution on how to do your classes, SOAP::Lite is not it at all. Wondered why its development ground to a halt, I don't think it's coincidental.

Re: SOAP Modules (OO or not?)
by perrin (Chancellor) on Jun 30, 2007 at 20:28 UTC
    Don't do that. SOAP really has nothing to do with object-oriented programming and doesn't really fit with it. You can make a class and have class methods called via SOAP, but there's no good way to make SOAP call methods on an object. In short, write your methods as class methods.
      I'm probably misunderstanding your post, but you can place method calls on soap objects. At least, on my laptop :) Here's an object I have in a little script in my cgi-bin:
      #!/usr/bin/perl use SOAP::Transport::HTTP; SOAP::Transport::HTTP::CGI->dispatch_to('Object')->handle; package Object; sub new { my $class = shift; $class = ref($class) || $class; return bless { '_cache' => [] }, $class; } sub set { my ( $self, $arg ) = @_; $self->{'_field'} = $arg; push @{ $self->{'_cache'} }, $arg; } sub get { shift->{'_field'} } sub all { shift->{'_cache' } }
      Here's a simple client:
      #!/usr/bin/perl use strict; use warnings; use SOAP::Lite +autodispatch => uri => 'http://www.perlmonks.org/Object', proxy => 'http://localhost/cgi-bin/soap.pl'; my $obj = Object->new(); for ( qw'So how is it possible that it stores and returns these? ???' +) { $obj->set( $_ ); print $obj->get, "\n"; } print join ' ', @{ $obj->all };
      And sure enough, it prints:
      So how is it possible that it stores and returns these? ??? So how is it possible that it stores and returns these? ???
      I'm not quite sure how SOAP::Lite does this - some sort of session? And not even under mod_perl or anything, frankly I don't quite get it...
        I suspect SOAP::Lite is doing some additional work to serialize the blessing of the hash and move the hash back and forth when you call methods on it. I doubt this will work if you try to call it from another language, since AFAIK the SOAP spec doesn't support this.
      Fair enough that SOAP doesn't really have anything to do with OO, however, and this is the bit that i'm really asking about...

      When SOAP dispatches to my module and method, the first thing passed to that method is the name of module, which leads me to think that it is being called in an OO context, and so i should bless it once i get inside.

      That would then keep all the code within the module all OO.

      Am I missing something? I'm not talking about treating it like an object when I pass it back through SOAP, although that would work fine too, so where's the harm?

        When SOAP dispatches to my module and method, the first thing passed to that method is the name of module, which leads me to think that it is being called in an OO context, and so i should bless it once i get inside.

        When a method receives a class name, not a blessed reference, it is being called as a class method. If you want to use OO features like inheritance, you can continue to call the other subs as class methods. You don't need to though.

        sub foo { my $class = shift; $class->bar(); # call bar() as a class method }

        I'm not talking about treating it like an object when I pass it back through SOAP, although that would work fine too, so where's the harm?

        That actually wouldn't work at all unless you did a lot of crazy workarounds. The XML serialization that SOAP uses is intentionally language-agnostic, so it has no way to represent the concept of something being blessed into a class.