The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Sloth::Manual::Architecture - how Sloth works

The Anatomy of a Sloth

    He who loves practice without theory is like the sailor who boards ship
    without a rudder and compass and never knows where he may cast.

Sloth is a simple framework, with not a whole lot to it, but by understanding how each component interacts, you'll be able to use it all much more efficiency.

The Big Picture

It helps to consider the flow of a request through the application.

    +  $app->call
    |  $app->router->match => $resource
    `+  $resource->get_method_handler($request)
     |  $resource->process_request
     `+  $method->get_request_parser->parse($request)
     ||  $method->request_data_validator->process($input) => $clean
     |`- $method->execute($clean) => $entity
     `- $resource->get_representation->serialize($entity) 

In more detail:

Match the path to a resource

If no match is found, raise a 404 Not Found exception.

Get a method handler from the resource

If no method handler is available, raise a Method Not Available exception.

Get a request parser

If the method has request parser, try and get a request parser for the given content-type in the request, and parse the request. If no request parser can be found, throw a Unsupported Media exception.

Validate the request input

Validate path parts, query parameters, and the request content body, and return a clean data structure.

Execute the request

Given the clean data, run the request and return some sort of resource.

Represent the entity

Find a suitable representation, based on the users Accept header, and return the entity in a given representation. If no representation can be found, throw a Not Acceptable exception.

The Sloth Application

The Sloth module defines the Plack::Component that can be ran on servers, and can be considered the "entry-point" or "event-loop" of your application. A Sloth application requires very little, and the essential attribute is resources. Let us consider the following example application:

    MyLittlePony
    MyLittlePony::Resources::Pony
    MyLittlePony::Resources::Pony::GET
    MyLittlePony::Resources::Pony::FoodStore
    MyLittlePony::Resources::Pony::FoodStore::PUT
    MyLittlePony::Representations::PNG

Resources

resources defines a list of all possible resources in your application. As you will likely have a large amount of these, Sloth automates this discovery for you, by looking in the ::Resources namespace of your application. In the MyLittlePony application we define 2 resources - Pony and FoodStore.

Each resource is an instance of Sloth::Resource which contains, amongst other things, a list of applicable methods and representations, and also provides an implementation of handling a request and appropriately dispatching it. Note that a resource doesn't have any type of logic behind it - that's down to the methods.

A resource defines a single path, which is the URI that it is exposed from, relative from the root of the application. This path is specified in a format compatible with Path::Router. For example, the Pony resource might live at the following path:

    sub path { 'pony/:id' }

This would match paths such as pony/42 and pony/alfred. Note that pony/alfred matches but is not valid, in our application. This validation will be addressed later. The :id part signifies a path variable, and will be passed into each Sloth::Method as part of the user parameters.

Resource Methods

A resource can have a set of associated methods. Each method is an instance of Sloth::Method, which provides a general implementation to handle a request. You should consider a method object to work very much like a single method in a class - you call it with a set of parameters and get something back.

Method classes live under the resource namespace. In our example application this means that Pony resources can be accessed via GET, and a pony's FoodStore can be modified via PUT.

In this case, the set of parameters is automatically derived for you from the query parameters, and the path part (as mentioned above). However, the set of parameters has not yet been sanitized and while values are present they might not be what you are looking for. Sloth uses Data::TreeValidator to validate user input. We might want to validate our Pony resource to make sure the ID is correct, for example:

     # in package Resource::Pony::GET
     use Data::TreeValidator::Sugar qw( branch leaf );
     use Data::TreeValidator::Constraints qw( type );
     has request_data_validator => (
         default => sub {
             branch {
                 name => leaf( constraints => [ type('Num') ] )
             }
         }
     );

This means that pony/42 is still valid, but pony/alfred is now invalid. Trying to GET pony/alfred will result in error 400, bad request, with the error message serialized into the response body.

Once validation passes, the control passes down to the method to fulfil some sort of action, be that fetch something from the database or launch nuclear missles. This all happens with the execute method. Let's implement a way to GET ponies:

    sub execute {
        my ($self, $input) = @_;
        return $self->c->pony_store->get($input->{id});
    }

Representations

Once a method returns something, we need to convey it back to the user. REST allows for the user to specify the format, so Sloth allows for multiple representations to be around. Representations live under the ::Representation namespace of your application, and are objects that do the Sloth::Representation role. In our MyLittlePony application, we have 1 representation which is PNG.

Representations are checked in the order of a clients Accept header, and the first one that matches will be used. Matching is done by using the "content_type" in Sloth::Representation value, which can either be a string or a regular expression.

When a valid representation is found, the resource returned from the method is passed through to the serialize method, which is then expected to return data to place in the response body.

And that's it!

AUTHOR

Oliver Charles

COPYRIGHT AND LICENSE

This software is copyright (c) 2011 by Oliver Charles <sloth.cpan@ocharles.org.uk>.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.