Bright Content Design Document: Web Triggers

Trigger as a URI

The essence of a web trigger is to POST or make some other HTTP request to a URL in order to "trigger" some action. There are two aspects of this that are important, the receiver of the trigger and the caller.

Location of Triggers

If we consider a trigger as simply a potentially disparate resource, then really we have abstracted them to essentially be the Web. This is OK, but we need a more integrated way of discovering and using triggers. One way to do this is via provision service that essentially is responsible for connecting a trigger provider with a consumer. One way for a provisioning service to function is to supply the URI of the trigger. An application might be given a list of triggers to call on a given action and simply get the URI and make whatever the required request is.

Another way to think of a provision service is as a proxy of sorts. The trigger request is sent to the proxy/provision URL which then dispatches it to the correct URL. This adds the benefit of more gracefully handling recursive requests as well as load balancing. More importantly, the provisioning dispatcher can have knowledge of any kind of trigger without placing any constraints on the caller.

Provisioning Use Case

One example of where a provisioning service could be used is in the Blog Admin. Currently, we simply use the store directly to save entries. This is bad because if we wanted to distribute the services or abstract the client to be a generic AtomPub client, then we have a lot of work to do. It also does not promote the RESTful qualities of BC. The better solution would be to expose the AtomPub interface to the Store as a trigger endpoint. This is beneficial because this allows a consistent pattern of wrapping the service call. So, when we add something like video blogging, the interface point can be continue to be used abstractly while the provision dispatcher handles the triggering of the correct handler, some video media type enabled AtomPub implementation.

This pattern is very powerful in that it is similar to that used in the current Annotations implementation. A comment is simply a type of annotation, so the comment URL simply wraps the more generic annotations URL.


(Original Page)

Many Web publishing systems with plug-in architectures use classic call-backs for plug-ins. A good example is the Weblog engine PyBlosxom. Plug-ins register call-back as a Python callable such as cb_start (called when the engine is initialized), cb_prepare (called at the beginning of each HTTP request to the engine). WSGI opens up a more flexible alternative approach in such systems. We call these Web triggers (see below for notes on the name).

All events to be handled by plug-ins are exposed as URL such as:

/brightcontent/trigger/...

The URL prefix should be flexible. This is probably a matter of signaling to the chosen dispatcher (e.g. Routes) which URL patterns are reserved for Web triggers. Each plug-in listens for a particular URL pattern for each event that it cares about. Events are propagated through the plug-ins by having something make an HTTP call back to the bright content server using a trigger URL. Some events might be triggered by the core BC engine itself (e.g. one should be triggered upon launch of the Web server, so that plug-ins can initialize themselves). Others might be called from other plug-ins, or even client-side tools.

The actual invocation of the URL can be made either by the equivalent of urlopen('http://example.com//brightcontent/trigger/event') or using a tool such as Paste recursive to mock up such a URL invocation. If the invocation is exposed to tools over the network it may open up a security issue, which is discussed below:

Use-case/example

For example:

The above example is a bit contrived: in many cases a good comment plug-in would handle the 3 tasks of spam detection, bad content database update and spam comment removal, but there's no reason the plug-in should not manage its own flow-of control via triggers, and the advantage of this is that third parties could register plug-ins that extend the comments plug-in in new ways, by listening for the triggers.

In general, there would be a core set of triggers launched by the BrightContent engine, but the community is free to set their own trigger conventions.

The above example also skirts some questions of URL and HTTP convention. In a real-world comments system a better scheme might be URLs such as something such as /brightcontent/plugins/comments/new-comment/ (generally invoked thought HTTP PUT). HTTP POST to /brightcontent/plugins/comments/check-comment/... for spam checking, and which results in an addition to the store only if found to be spam-free.

Security

Since a trigger may be accessed via HTTP, a trigger may provide a public interface to custom features. With this in mind HTTP Auth can be used to secure a trigger resource. For example, consider a stats plug-in at the resource:

/brightcontent/trigger/stats/entries_by_author/elarson

This plug-in might find all the entries (including comments) made by an author. This type of request might be resource intensive or contain private information. The trigger could then be protected using HTTP Authentication when requested from a domain outside of a set of trusted clients. If the resource is requested internally by the BrightContent engine, the security measures could be ignored or enforced.

We strongly recommend that the specification for every plug-in documents its security implications if invoked by a trigger over the network.

Configuration

The base URL for triggers should be the base URL for the Weblog, and there should be a new config parameter for the trigger path component, e.g.

trigger = trigger

In the Bright Content section of the INI file.

What about REST?

We believe that the Web triggers idea is very RESTful. The chain of WSGI modules that "listen" for the URL *is* the Web resource represented by the URL, and all the ideas of REST apply as usual. For example, if the WSGI handlers are expected to modify state based on the event, it should be invoked using HTTP POST to the URL rather than GET.

Why call them "Web triggers"?

People tend to think of DBMS technology when they think of the term "trigger". But if you boil it down even in DB terms, a trigger is is just a marker to invoke an action automatically upon an event. It's like the Observer design pattern. In this case we are using Web technology as much as possible, which means that a Web invocation is the best way to signal an event. The combination of the agreed convention for the event URL and the WSGI components designed to perform some action upon seeing this event constitutes a "trigger" by means of the "Web".

Other examples of plug-in approaches

Listed in part for skimming of ideas and in part for "ewww, we don't want that" reaction :-)

Bright_Content/Architecture/Web_triggers (last edited 2008-11-24 18:46:30 by localhost)