Superseded by WITW: SOAP RPC (V2), 24 Feb 2005.

WITW Part II: SOAP RPC

Volume 8, Issue 25; 18 Feb 2005; last modified 08 Oct 2010

Keeping track of your location with SOAP RPC.

My second interface to Where In The World is a set of methods that you can invoke using SOAP RPC. I'm not sure I really understand all the jargon yet, but I think the salient bits are:

The target SOAP node

That's “http://norman.walsh.name/2005/02/witw/soap” for the “where is someone” services and “http://norman.walsh.name/2005/02/witw/ami/soap” for the “where I am” services that require authentication. (In fact, the latter node will perform all of the services.)

The namespace of the services

That's “http://norman.walsh.name/witw”. I'd have made that a dated URI, but I'm using Perl’s SOAP::Lite module to do the implementation and there was some weirdness in the way that the namespace name was mapped to the Perl module name. I decided to just punt.

The names of the methods

They are “user”, “is”, “nearby”, “atlatlong”, and “atlandmark”, described below.

As you may have noticed, I've decomposed things a little bit differently. I did that to make some of the return types more manageable.

User

The user method returns information about a userid:

user(xs:string userid)
    throws UnknownUser;

It returns the userid, the name of the user, a hash (in the mbox_sha1sum-style of FOAF) of the user's email address, and the uri associated with the user.

If the specified userid is unknown, the service faults.

Is

The is method returns information about the location of the specified userid.

is(xs:string userid)
    throws UnknownUser, UnknownLocation;

It returns the userid, the date when the location was specified, the latitude and the longitude specified by the user.

It faults if the userid is unknown or if the user has not specified a location.

Nearby

The nearby method returns information about landmarks that are close to the location of the specified userid.

nearby(xs:string userid,
       xs:string units= "mi",
       xs:decimal distance= 50.0)
    throws UnknownUser, UnknownLocation, InvalidUnits, InvalidDistance;

The units and distance parameters are optional. If specified, units must be one of “mi”, “km”, “m”, or “ft”. The default distance is 50 miles (about 80km).

It returns zero or more sequences of landmarks: the name of the landmark, its latitude, longitude, any URI associated with the landmark, and its distance from the user.

It faults if the userid is unknown, if the user has not specified a location, if the units are invalid, or if the distance is invalid.

At Latitude and Longitude

The atlatlong method allows a user to specify their location. You must use the authenticated SOAP node (http://norman.walsh.name/2005/02/witw/ami/soap) in order to access this method and the userid specified must match the authenticated user.

atlatlong(xs:string userid,
          xs:decimal latitude,
          xs:decimal longitude)
    throws AuthorizationRequired, InvalidUser, UnknownUser, InvalidLatitude, InvalidLongitude;

It returns the userid if it succeeds or throws a SOAP fault.

At Landmark

The atlandmark method allows a user to specify that they are at a particular landmark. Like the atlatlong method, you must use the authenticated SOAP node (http://norman.walsh.name/2005/02/witw/ami/soap) in order to access this method and the userid specified must match the authenticated user.

atlandmark(xs:string userid,
           xs:string landmark)
    throws AuthorizationRequired, InvalidUser, UnknownUser, UnknownLandmark;

It returns the userid if it succeeds or throws a SOAP fault.

Sample Code

On the assumption that any who's read this far won't be scared off by a few lines of code, here's a short Perl script that returns the latitude and longitude of a user.


      #!/usr/bin/perl -- # -*- Perl -*-

use strict;
use SOAP::Lite;

my $usage = "$0 userid\n";

my $userid = shift @ARGV || die $usage;

my $soap = SOAP::Lite->new();
$soap->uri("http://norman.walsh.name/witw");
$soap->proxy("http://norman.walsh.name/2005/02/witw/soap");

my $result = $soap->user($userid);
if ($result->fault()) {
    print STDERR "SOAP fault: ", $result->faultcode(), "\n";
    print STDERR "\t", $result->faultstring(), "\n";
    exit 1;
}

my ($name, $email, $uri) = $result->paramsout();

$result = $soap->is($userid);
if ($result->fault()) {
    print STDERR "SOAP fault: ", $result->faultcode(), "\n";
    print STDERR "\t", $result->faultstring(), "\n";
    exit 1;
}

my ($date, $lat, $long) = $result->paramsout();

$lat = sprintf("%2.2f%s", abs($lat), $lat > 0 ? "N" : "S");
$long = sprintf("%2.2f%s", abs($long), $long > 0 ? "E" : "W");

print "$name was last seen at $lat, $long.\n";
print "That was on $date.\n";

    

This morning, if you pass it ndw, it tells you I'm at home:

$ perl witw.soap.pl ndw
Norman Walsh was last seen at 42.34N, 72.45W.
That was on 2005-02-17T21:35:42Z.

To satisfy my own curiosity, I wrote a Perl script to get the same information using the brute force API:


      #!/usr/bin/perl -- # -*- Perl -*-

use strict;
use XML::XPath;

my $usage = "$0 userid\n";

my $userid = shift @ARGV || die $usage;

my $uri = "http://norman.walsh.name/2005/02/witw/is/$userid";

# hack!
my $data = "";
open (F, "wget -q -O - $uri |");
while (<F>) {
    $data .= $_;
}
close (F);

my $xpath = new XML::XPath($data);
$xpath->set_namespace("is", 'http://nwalsh.com/xmlns/witw-is#');

if ($xpath->exists("//is:unknown-user")) {
    print STDERR "Unknown user: $userid\n";
    exit 1;
}

my $name = $xpath->findvalue('//is:user/is:name');

if ($xpath->exists("//is:unknown-location")) {
    print STDERR "The whereabouts of $name are unknown.\n";
    exit 1;
}

my $lat = $xpath->findvalue('//is:location/@lat');
my $long = $xpath->findvalue('//is:location/@long');
my $date = $xpath->findvalue('//is:location/@date');

# XML::XPath is doing some bizarro Perl overloading.
# Skip the pretty printing.

print "$name was last seen at $lat, $long.\n";
print "That was on $date.\n";

    

The two styles of API are clearly quite different, but I'll reserve judgement until I've done a few more experiments.