SOAP is here, wash yourself

pudge on 2002-03-05T01:29:09

Journals now support SOAP. This is experimental and subject to change, though I hope that it won't change significantly, except to fix bugs and improve in various ways.

There are five methods.

  • add_entry(LIST)
    add_entry(SUBJECT, BODY)

    Add an journal entry. Either pass two arguments, SUBJECT and BODY, or pass a list of key-value pairs, where the allowed keys are subject, body, discuss, posttype, tid.

    discuss is a boolean for turning on discussions. posttype is an integer specifying one of the allowed post types. tid is an integer specifying the one of the topic IDs (topics aren't really used in journals on use.perl.org right now). These things will take your defaults if left unspecified.

    Method returns the unique ID of the new entry, or false for failure.



  • modify_entry(ID, LIST)

    Similar to add_entry, but modifies an existing entry, specified by ID. Journal ID can also be seen in the header of the particular journal entry in the web interface. Supply only the keys that are to be modified.

    Method returns the same unique ID if successful, or false for failure.



  • delete_entry(ID)

    Deletes entry specified by given ID.

    Returns true for success, false for failure.



  • get_entry(ID)

    Returns hashref with data for given entry, or false for failure.

    Data currently includes the URL to the journal entry, the URL to the journal discussion, the ID of the journal, the ID of the journal discussion, the body, the subject, the posting date, the topic ID, the user ID, the user nickname, and the posttype.



  • get_entries(UID, LIMIT)

    Returns arrayref of hashrefs, with data for journal entries for user with given UID, or false for failure. Returns most recent LIMIT number of entries, with three keys for each entry: URL to the journal entry, the ID of the journal, and the subject.





Now, how to use it? I gave an example recently, but here is another. Note that I use SOAP::Lite (although any SOAP client should work) and I use my own local Netscape cookie file on Mac OS to provide authentication. If you don't properly authenticate, you will be able to use the get_* methods, but not the others; and, of course, you can only add/modify/delete your own entries.

#!/usr/bin/perl -w use strict; use HTTP::Cookies; use SOAP::Lite;

my $host = 'use.perl.org'; my $uri = "http://$host/Slash/Journal/SOAP"; my $proxy = "http://$host/journal.pl"; my $cookie_file = "$ENV{HOME}Netscape Users:Chris Nandor:MagicCookie";

my $cookie_jar = HTTP::Cookies::Netscape->new; $cookie_jar->load($cookie_file);

my $journal = SOAP::Lite->uri($uri) ->proxy($proxy, cookie_jar => $cookie_jar);

# now, the methods

my $recents = $journal->get_entries( 1, 10 )->result; my $recent = $journal->get_entry( $recents->[0]{id} )->result;

my $new_id = $journal->add_entry( 'this is a test again', 'ha!' )->result; $journal->modify_entry( $new_id, body => 'uh!' );

# this one is dangerous, be careful # $journal->delete_entry( $new_id );

__END__


I hope this makes your journal experience a more pleasurable one. Note that you shouldn't abuse this by making a ton of entries, because I'll be angry, and so will your fellow users who are set to receive a message each time you post a new entry.

Two more things: there currently is no nickname->uid mapping (although get_entry returns the nickname and uid). There will be at some point, probably. Also, the only way to get recent journals is via RSS, which may suit whatever evil purposes you have.

Special thanks to jjohn for his help in figuring some of this stuff out.


You the b0mb

jjohn on 2002-03-05T01:53:44

Nicely played, Pudge-daddy. When I have the
cycles, I'll post some groovy emacs macros on my journal for this service. You know, you've made Slash one step closer to Manilla now? :-)

Re:You the b0mb

pudge on 2002-03-05T01:58:47

Except that Slash does more, is more extensible, and doesn't cost a thousand bucks!

posting a lot

jamiemccarthy on 2002-03-05T02:43:44

To forestall abuse by posting a lot of entries, how hard will it be to stick a formkey onto journal creation? Do

formkeyHandler('max_post_check', 'journals', $formkey, $msg_ref)

and create a var called

max_journals_allowed ... simple right?

Re:posting a lot

pudge on 2002-03-05T03:05:45

Yes, we can do that, and in fact we do, but the default limit is 30.

Although, we don't have formkeys turned on for SOAP yet ... I am going to be looking into that as time permits.

WWW::UsePerl::Journal

koschei on 2002-03-07T03:07:39

Hmm. Now to rewrite WWW::UsePerl::Journal to make use of SOAP.

How does one get the recent journals via RSS anyway? Last time I looked it returned invalid URLs in the RSS.

Re:WWW::UsePerl::Journal

pudge on 2002-03-07T03:25:10

The RSS should be fine, it has been for some time now.

Re:WWW::UsePerl::Journal

koschei on 2002-03-07T03:35:47

Hmm. Hang on: is that rss for recent entries of the person or rss of the journal system as a whole?

The url that provides incorrect urls is:
http://use.perl.org/search.pl?content_type=rss&op=journals

Re:WWW::UsePerl::Journal

pudge on 2002-03-07T05:26:50

I never knew about this RSS "feed". I was referring to http://use.perl.org/journal.pl?op=top&content_type=rss. If you know of bugs, please file a bug report, else they won't get fixed!

Re:WWW::UsePerl::Journal

koschei on 2002-03-07T13:41:31

Grr. Logged. After spending a few minutes trying to remember my sf password since anonymous bug reports are disabled. And SF seem to believe that this browser shouldn't be able to log into their website (it did, fwiw).

Anyone else find the sidebar in sf just about completely useless and just taking up space? (I'm on a rev C iMac at present - not much screen real estate, and I had to regress to 8.6 to get remote access working, bloody thing).

Come to think of it: anyone got a spare new iMac/iBook so I can run OS X? =)

At least I have MacPerl and MacVim installed. Now I just need to read about MacPerl a bit more so I can do some fun stuff with it =)

Re:WWW::UsePerl::Journal

koschei on 2002-03-07T13:49:16

I should note that the 'Grr' is aimed at sf, not you. You're very lovely.

Re:WWW::UsePerl::Journal

pudge on 2002-03-07T14:28:22

We had to disable anonymous bug reports because we had too many trolls posting bug reports. Welcome to the life of running Slashdot. :-)

MacPerl can run the script I gave for SOAP::Lite, so that's one fun thing you can do with it! MacPerl 5.6.1r1 is due any day now, too.

Re:WWW::UsePerl::Journal

koschei on 2002-03-07T14:55:20

I just need to have CPAN.pm working so I can install stuff (easily). It's currently hanging after I enter my continent (from a cmd-1 'perl -MCPAN -eshell').

I'm probably just going about it the wrong way. I'll be looking into it on the weekend =)

It's a nice piece of work mind you =)

Re:WWW::UsePerl::Journal

pudge on 2002-03-07T15:17:52

Try:

#!perl
use CPAN;
shell();

The one-liner will complete and then return, so it is not good for interactive scripts. :-) If you want an interactive command-line, get and install MPW (or just ToolServer, if you have something that can talk to it, like BBEdit, but MPW is superior, because ToolServer cannot call other tools, so you can't do "perl -le 'print `files`'" etc., because ToolServer itself is what allows you to call said other tools! :-).

Re:WWW::UsePerl::Journal

rjray on 2002-03-11T00:51:29

You'll want to be careful in how you handle the checking for SOAP at build-time and run-time. Don't want to force people into installing something, better to give them the choice. Unless they already have it installed, of course :-).

--rjray

Re:WWW::UsePerl::Journal

koschei on 2002-03-11T03:47:30

Hmm. I'm more of the philosophy: why have two versions of the same code?

At the very least, the more modules that make people have SOAP client software, then the more SOAP server software there can be.

That said, is SOAP::Lite that difficult to install?

Re:WWW::UsePerl::Journal

pudge on 2002-03-11T04:06:27

If you're talking about using SOAP versus trying to read, parse, and post data by emulating a web client, there's no contest: use SOAP. The web client interface is guaranteed to change some day in subtle ways that will break any code you have. The SOAP interface is not. I won't say it's guaranteed to not change, but I'll try not to change it. :-)

So yeah, if it were me, I would require users to use SOAP::Lite, or some other SOAP client module.

Username = UID mapping?

rjray on 2002-03-11T00:54:04

Any idea when we'll see a method for getting the ID from the username? I've already got two scripts based on this ready to go, but it pains me to see users forced to look up the UIDs :-).

--rjray

Re:Username = UID mapping?

pudge on 2002-03-11T02:45:49

No, no idea yet. What I think might be best, currently, is to have a SOAP interface for the users stuff. So right now we have Slash::Journal::SOAP, and maybe add a Slash::Users::SOAP. One thing I am sure of is that I don't want to go further until I have a better sense of direction, so now would be a good time to give me any thoughts anyone might have on the subject. :-)

Re:Username = UID mapping?

rjray on 2002-03-11T23:35:09

Hurm-- I'd love to help out with ideas, especially since this is going to be referred to several times in my SOAP chapters for the book on web services I'm writing :-). I'm not that familiar with the Slash code itself, though, and I'm not at a good place to be trying to dive into something new, either.

I would start with a fairly basic approach that lends itself easily to adding onto later. There is no need for user-add or user-delete functions at the SOAP level, I think we can all agree that those are better left someplace !SOAP. Basic information retrieval by UID, discerning UID from a given username, and some degree of user-info updating for users that have adequate credentials on the UA, these would be a good start. Even the latter, user-update, is less important at this stage than information-retrieval.

--rjray

Re:Username = UID mapping?

pudge on 2002-03-12T03:38:57

Those are similar to my thoughts, thanks.

However, a problem I see is with how to get this all to play nicely together. What I mean is this: the uri() for Journals is "http://$host/Slash/Journal/SOAP". But the uri() for getting information about users would be something like "http://$host/Slash/Users/SOAP". Is this too unwieldy?

Application the first

rjray on 2002-03-12T06:40:01

Here's something I've put together as an early example for my chapter on using the toolkits (the one that will introduce each of the SOAP and SOAP::Lite packages, before moving on to bigger code). This'll do until we get "native" RSS feeds of individual journal. :-)

OK, scratch that. Getting the code to look right in preview is killing me. Instead, pull it down from here. Pudge, if you tell me how to make my code look purdy like yours, I'll update this...

--rjray

Re:Application the first

pudge on 2002-03-12T13:16:15

I've been holding off announcing it, but use the pseudotag <ECODE>. It still needs some work, and has some caveats, which I hope to deal with and announce soon.

Re:Application the first

rjray on 2002-03-12T23:59:17

Let's give it a try, then... here 'tis:


#!/usr/bin/perl -w

use strict;

use SOAP::Lite;
use XML::RSS;

my $user = shift ||
    die "Usage: $0 userID [ usernick ]\n\nStopped";
my $nick = shift || "#$user";

my $host        = 'use.perl.org';
my $uri         = "http://$host/Slash/Journal/SOAP";
my $proxy       = "http://$host/journal.pl";

my $journal = SOAP::Lite->uri($uri)->proxy($proxy);
my $results = $journal->get_entries($user, 15)->result;
my $rss     = XML::RSS->new(version => '1.0');

$rss->channel(title       => "use.perl.org journal of $nick",
              'link'      => $proxy,
              description => "The use.perl.org journal of $nick");
$rss->add_item(title  => $_->{subject}, 'link' => $_->{url})
    for (@$results);

print STDOUT $rss->as_string;

__END__

(Looks much better in preview, thanks...)

--rjray

Application the Second

rjray on 2002-03-13T00:29:29

Just used this to post a test-entry into my journal. It's probably about on-par with the test script pudge was using a while back, except that the path to the cookie file is UNIX-ish instead of Mac-ish (and File::Spec wouldn't really help here, because the different Netscape platforms save their user data in differently-formed paths). It also allows for command-line arguments for title and whether to allow discussion. It also allows a command-line-provided filename to provide the body, or in absence of it reads from STDIN. It doesn't handle the other options to add_entry because they're integer-oriented, which would be useless to an end-user without some text-to-value mapping (pudge: another subject for our off-line architecture discussion). But it's a start, and might be good cut-and-paste fodder for someone else. I'll be adding the non-Netscape cookie support later.


#!/usr/bin/perl -w

use strict;

use Getopt::Std;

use HTTP::Cookies;
use SOAP::Lite;
use XML::RSS;

my %opts;
getopts('c:u:m:f:', \%opts) or die <<"USAGE";
Usage: $0 [ -m title ] [ -f file ] [ -c yes|no ]
where:

-m title        Provide title for the journal entry
                (default is command name-based)
-f file         Read the journal entry from FILE instead of STDIN
-c yes|no       Allow or disallow comments
                (default is to let your use.perl.org default stand)

USAGE

my $title       = $opts{'m'} || "Generated by $0";
my @discuss     = (exists $opts{c}) ?
                      (discuss => $opts{c} =~ /yes/i ? 1 : 0) : ();
my $readfh;
if ($opts{f})
{
    open(FILE, "< $opts{f}") or die "$0: Error opening $opts{f}: $!\n";
    $readfh = \*FILE;
}
else
{
    $readfh = \*STDIN;
}
my $body = join('', <$readfh>);

my $host        = 'use.perl.org';
my $uri         = "http://$host/Slash/Journal/SOAP";
my $proxy       = "http://$host/journal.pl";
my $cookie_file = "$ENV{HOME}/.netscape/cookies";

my $cookie_jar  = HTTP::Cookies::Netscape->new;
$cookie_jar->load($cookie_file);

my $journal = SOAP::Lite
                  ->uri($uri)
                  ->proxy($proxy, cookie_jar => $cookie_jar);
my $result = $journal->add_entry(subject => $title,
                                 body    => $body,
                                 @discuss)->result;
print $result ?
    "New entry added as $result\n" : "Entry was not added\n";

__END__

--rjray

Re:Application the Second

pudge on 2002-03-13T02:08:20

Yeah, the other things need mappings, and they are more things that may not be in the same place in the code, like the topics mapping.

Stop using SOAP::Lite until it is fixed!!!

IlyaM on 2002-04-07T13:59:40

I guess you use SOAP::Lite to implement SOAP server. You should disable it immediately. Really. For more info why see my journal entry.

Re:Stop using SOAP::Lite until it is fixed!!!

rjray on 2002-04-08T21:47:42

Ilya... from the conversation we've had in e-mail, I think you might want to consider writing up something for the frontpage, as a story. I think this warrants it. Not the example code you gave me, just the warning itself.

--rjray