Wednesday, April 1, 2009

API Design: Beautiful Interfaces

This is part of a series on Web API design. The intro post is here.

When some developers think about the Google Maps API, they may envision a sea of GMarkers, GPolygons, GScaleControls, GOverviewMapControls, and the like. But really, it boils down to 2 things: GOverlay and GControl.

These two classes are interfaces in the API, and every class that is a visual item on the map extends from one of those two. Conceptually, a GOverlay is something that moves when the map moves and is somehow related to latitude/longitude coordinates, and a GControl is something that always stays in the same place, regardless of map movement. The screenshot below points to various examples in a standard maps mashup:

To add one of these to the map, a developer just calls addOverlay or addControl:

map.addControl(new GScaleControl());
map.addOverlay(new GMarker(new LatLng(37, -122));

To remove them, they call removeOverlay or removeControl.

There are some mapping APIs out there with calls like addMarker, addPolyline. This is is a bad idea for several reasons. It means you need an additional method each time you add a new visual class (bloating your API), and it likely also makes it hard for developers to extend the API. With generic methods like addOverlay or addControl, you can add a custom extension the *same way* you add a native class - so newbie developers don't have to learn a new syntax to add one to their map.

Along with using generic methods for adding stuff to the map, we can also take advantage of the interface to make our events more generic. A developer can listen to "addoverlay" or "removeoverlay" to find out when any overlay has been added to the map, and when they listen to a "click" event on the map, their callback gets passed in whatever GOverlay was clicked on. This means that whenever we add a new type of overlay to our API, the developer can continue using the same events they were before. We do often add specific events for each overlay later, but it's nice that the generic ones come for free.

And something for the advanced developers...

These interfaces make our API infinitely extensible in a standard way, and they're the reason I used the API for my personal and research projects even before working for Google. If I have a fundamental aesthetic issue with our GLargeMapControl3D, then I can simply create my own control (ExtLargeMapControl). If I want to visualize 5,000 markers, and GMarker is simply too full-featured and heavyweight for the job, then I can create my own lightweight marker (MarkerLight). If I want to visualize my points as <div>-based bar graphs instead of <img>-based markers, then I can create my own overlay (Bar).

To extend the interfaces requires defining only a few minimal methods:

GOverlay: initialize, redraw, remove

The initialize method, called when addOverlay is invoked, should create DOM objects for the overlay and append them to the desired map pane (there are several). The redraw method is called whenever the map moves, and it should re-position the overlay depending on the new latitude/longitude -> pixel mapping. The remove method, called when removeOverlay is invoked, should clean up any DOM objects created by the overlay. More info and an example is in the docs.

GControl: initialize, getDefaultPosition

The initialize method, called when addControl is invoked, should create and return the div for the control. The getDefaultPosition method should returns the recommended position for the control. There is no remove method, since the initialize method returned a <div> that the map can remove whenever removeControl is invoked. More info and an example is in the docs.

Using just these methods and some JavaScript/CSS skills, a developer can create anything their hacker heart desires. Custom controls and overlays account for 15/20 of the libraries in our official utility library, another 15 of the libraries listed in Mike William's list of 3rd party extensions, and based on my experience, many more are likely floating around in developer's code on the web.

Don't forget the actual API engineers...

Along the same lines, these interfaces also make API development easier for internal developers. If they want to add a visual class to the API, they just need to figure out whether it's a control or an overlay, define the methods, document that the new class exists, and external developers will use their existing familiarity with addControl or addOverlay to add it to their map.

It can't all be fluffy rainbows and unicorns...

We've certainly made a few mistakes along the way with the interfaces - but this post is getting long, so I'll save those for later.

To sum it all up...

The interfaces are easy for newbie developers to understand, easy for advanced developers to extend, and easy for internal engineers to implement. Beautiful.