Zope, Web Services, and why it should work and why I'm frustrated it doesn't

From Jon Udells's Radio: Jeffrey P Shell on Zope's lizard brain. I had a nice response to a recent column on Zope from Jeffrey P Shell, a longtime Zopista and former Digital Creations guy who has decamped to the skiiing life in Utah. Jeffrey wrote one of the first BYTE columns on Python, longer ago than the web seems to remember. Anyway, in my column I talked about scripting Zope from the outside, using the RESTian approach of reverse-engineering its HTML management forms and calling them as URLs. I knew that XML-RPC was another way to do this. Jeffrey pointed out a third, little-known approach that taps into Zope's "lizard brain."

This third way is one of the neat things about the foundations on which Zope was built. Back in the wayback days, there was The Python Object Publisher, also known as Bobo. When Jim Fulton first came to what was then Digital Creations (now Zope Corporation), he was sent to a conference to give a talk on CGI programming. During the trip, Jim realized that the way of CGI programming at the time was pretty terrible - as a developer, one would often spend more time dealing with various CGI related issues such as finding out if certain fields came in from a form, casting them to the correct object type, etc.., than working on the actual program. It was easy to write a small CGI script, but it was hard to scale. And it wasn't very object oriented. So, Jim came up with Bobo, which was basically an ORB (Object Request Broker) that translated CGI calls into object calls, and marshalled data. It was a simple and beautiful concept - it meant that one could publish existing Python objects on the web with very little work. Certainly much less work than using CGI libraries that existed then. Furthermore, the publishing machinery was abstracted enough that different publishers could be plugged in - drop out plain CGI and put in FastCGI. Normally, that would have meant writing very different code. But not in the world of Bobo. There was even an ILU publisher.

What this all meant was that Bobo could take a web request like:

..../People/Elia/setAge?age:int=27

And turn it into an object call like:

People.Elia.setAge(age=27)

Note that it automatically converted the 'age' parameter to an integer. Anyways, other small toolkits found their way into Bobo - BoboPOS (persistent object system) and Document Templates. They were all open sourced and available for years. Digital Creations used these tools to make a more complete publishing platform called Principia, a closed source system that was eventually open sourced as Zope.

Zope has a lot of good and bad points, but it's still built around that basic notion of publishing objects on the web. Bobo became the ZPublisher package, BoboPOS became the ZODB (Zope Object Database), and DTML grew from a nice simple reporting language to the behemoth it is today as new and different uses and requirements were foisted on it throughout the years.

And, there was a scriptable remote procedure call interface for it as well, called BCI in the Bobo/Principia days, and ZPublisher.Client in the Zope days. Using the example above:

from ZPublisher import Client

Elia = Client.Object('http:..../People/Elia', username='bob', password='uncle') Elia.setAge(age=27)

pic = open('local/path/to/picture.jpg') Elia.setPicture(image=pic)

The first line after the import establishes a local Proxy object to a remote URL. Note that one can specify a username and password. From Bobo up to Zope 2.5.1 and the new Zope 3, security has always been an integral concept. So the methods we're calling here may only be callable by people with certain roles. Well, HTTP obviously has some built in notion of security, so ZPublisher and ZPublisher.Client have always made good use of this.

The next line calls the 'setAge()' method on the object 'Elia'. Ultimately, ZPublisher.Client generates the URL seen earlier, with proper authentication headers. It recognizes the value of 'age' locally as an integer, and adds the Bobo marshalling ':int' onto the CGI parameter.

The next two lines open a file object and pass it onto another method on Elia. ZPublisher.Client automatically knows to turn this request into a POST request, and uploads the file to the target URL.

Before the availability of FTP in Zope (which appeared in Zope 2), I used BCI scripts to upload local files to the server often.

So where am I going with this? Well first, I wanted to key Jon Udell, whom I've known online for years and whose articles on ComponentWare in BYTE back in 1994 I still consider worth reading today, onto this cool little Zope feature that's slipped into near obscurity. It shouldn't have.

Second, Dave Winer wrote in Scripting News today about how Google and Microsoft are getting all of the "scriptable internet" press that Manila was doing three years ago. Well, Bobo was doing this in 1996! Before XML-RPC, before Servlets, before Frontier 5.0, before many things. Although WebObjects was there. Other tools were there too, and everyone was developing their own (including me).

Now, like many products, the potential was never capitalized upon. At the time, there was no XML, so there was no common way to marshal data two ways. Even after the advent of XML, this notion was never siezed upon. Which is a shame really, XML-RPC could have been a great thing for Zope. Zope does support it, but XML-RPC just doesn't fit will with Zope's security model. Plus, all of Zope's protocol supports (FTP, WebDAV, XML-RPC) have been implemented differently. So, they can sometimes be awkward. Zope 3 promises to fix this, with a more unified development model and a ground up re-architecting. It's still based on the old concepts of Bobo, but is being built to handle the much more complex (as in size) web application demands of today. Here's hoping they do Web Services right. Zope should be kicking ass in this field, because the whole objects-on-the-web philosophy that Web Services seems to embody is what Zope has been built upon since its very very beginnings. And I know that Brian Lloyd - now Zope Corp's VP of engineering - has done some extensive research into how to do WebServices for Zope. The initiative is in good hands. It looks like it's stalled though.

Back to XML-RPC... It continues to annoy me that authentication wasn't thought of as part of the core protocol. Seeing "username, password" as arguments to all the Blogger and Manila API's just seems wrong to me. Maybe it's my upbringing through Bobo and BCI, but.. it just seems wrong!. One has to implement something like this to add support in to the basic XML-RPC modules for Python. Why does this have to be done? Because Zope's security is so deep and natural, there's just no easy way to authenticate a user temporarily from a username/password as arguments to a public method call. Which is as it should be, in my opinion. Zope's security model is great. It's methods are easy to call on the web. Why then can't I call a protected method easily from AppleScript's XML-RPC?