Articulate - A lightweight Perl CMS Framework


This is very much in alpha. Things will change. Feel free to build things and have fun, but don't hook up anything business-critical just yet!


  # (in bin/
  use Dancer;
  use Dancer::Plugin::Articulate;

Articulate provides a content management service for your web app. It's lightweight, i.e. it places minimal demands on your app while maximising 'whipuptitude': it gives you a single interface in code to a framework that's totally modular underneath, and it won't claim any URL endpoints for itself.

You don't need to redesign your app around Articulate, it's a service that you call on when you need it, and all the 'moving parts' can be switched out if you want to do things your way.

It's written in Perl, the fast, reliable 'glue language' that's perfect for agile web development projects, and currently runs on the Dancer and Dancer2 web frameworks.


Don't forget to install Articulate - remember, it's a library, not an app.

  # From source:
  perl Makefile.PL
  make test
  make install

Check out the examples in the examples folder of the distribution.

To add Articulate to your own app, you'll need to:

  • add it to your bin/ or similar (see example above) using either Dancer::Plugin::Articulate or Dancer2::Plugin::Articulate.

  • edit your config.yml to configure the components you want (check each of the components for a description of their config options - or just borrow a config from one of the examples)

  • write any custom code you want if you don't like what's there, and just swap it out in the config.

  • polish off your front-end, all the backend is taken care of!

Curious about how it all fits together? Read on...


Articulate is a set of components that work together to provide a content management service that will sit alongside an existing Dancer app or form the basis of a new one.

If you want to see one in action, grab the source and run:

  # If you have Dancer and Dancer::Plugin::Articulate installed:
  cd examples/plain-speaking
  perl bin/ -e dancer1

  # Or, if you have Dancer2 and Dancer2::Plugin::Articulate installed:
  cd examples/plain-speaking
  perl bin/app.psgi

You can see how it's configured by looking at


Notice that bin/ doesn't directly load anything but the Articulate plugin (which loads config into this module). Everything you need is in config.yml, and you can replace components with ones you've written if your app needs to do different things.

Request/Response lifecycle summary

In a route, you parse user input and pick the parameters you want to send to the service. Have a look at Articulate::Routes::Transparent for some examples. The intention is that routes are as 'thin' as possible: business logic should all be done by some part of the service and not in the route handler. The route handler maps endpoints (URLs) to service requests; structured responses are passed back as return values and are picked up by the serialiser.

Routes pass requests to services. A request contains a verb (like create) and data (like the location you want to create it at and the content you want to place there). See Articulate::Request for more details.

The service is responsible for handling requests for managed content. Articulate::Service delegates to a service provider, asking each in turn if they are willing to handle the request (normally the provider will dertermine this based on the request verb). A provider typically checks a user has suitable permission, then interacts with the content storage system.

Storage is controlled by Articulate::Storage. It delegates to a storage class which is configured for actions like get_item and set_meta.

Content is stored in a structure called an item (see Articulate::Item), which has a location (see Articulate::Location), the content (which could be a binary blob like an image, plain text, markdown, XML, etc.) and the associated metadata or meta (which is a hashref).

Before items can be placed in storage, the service should take care to run them through validation. Articulate::Validation delegates this to validators, and if there are any applicable validators, they will check if the content is valid. The content may also be enriched, i.e. further metadata added, like the time at which the request was made (consult Articulate::Enrichment for details).

After items are retrieved from storage, there is the opportunity to augment them, for instance by including relevant content from elsewhere which belongs in the response. See Articulate::Augmentation for details on this.

If at any time uncaught errors are thrown, including recognised Articulate::Error objects, they are caught and handled by Articulate::Service. Articulate::Service should therefore always return an Articulate::Response object.

Once the request finds it back to the Route it will typically be serialised immediately (see Articulate::Serialiser), and the resulting response passed back to the user.


The following classes are persistent, configurable components of the system:

Data Classes

The following classes are used for passing request data between components:

Other modules of interest


Articulate provides a very handy way of creating (or instantiating) objects through your config. The following config, for instance, assignes to the providers attribute (on some other object), an arrayref of four objects, the first created without no arguments, two created with arguments, and a final one created without arguments but using an unusual constructor.

    - MyProvider::Simple
    - class: MyProvider::Congfigurable
        verbose: 1
    - MyProvider::Congfigurable:
        lax: 1
        verbose: 1
    - class: MyProvider::Idiosyncratic
      constuctor: tada

For more details, see Articulate::Syntax.


A key part of the flexibility of Articulate is that objects often delegate functions to other objects (the providers)

Typically, one class delegates to a series of providers, which are each passed the same arguments in turn. Articulate::Augmentation is a good example of this. Sometimes the response from one provider will halt the delegation - see Articulate::Authorisation for an example of this.

Occasionally, only one provider is possible, for instance Articulate::FrameworkAdapter. In this case there is a substitution rather than a delegation.



Sets up the routes. This does not happen at construction so you can control the point at which routes are declared.



Please do not set this directly, use enable instead.


The packages which provide routes for Articulate. See Articulate::Syntax::Routes and Articulate::Role::Routes for more details.


The different working pieces of the Articulate app. Components all have access to each other indirectly and they provide features across Articulate; see Articulate::Role::Component for more details.


If you'd like to help build the core or the econsystem, you'll want to look at the file in the source distribution, which gives more technical information about how you can contribute to and work with Articulate.


Bug reports are an important contrubution and should be reported to the github issue tracker. You can also request new features this way. Pull Requests welcome!


Articulate is Copyright 2014-2015 Daniel Perrett. You are free to use it subject to the same terms as perl: see the LICENSE file included in this distribution for what this means.

Currently Articulate is bundled with versions of other software whose license information you can access from the LICENSE file.