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

NAME

SweetPea::Overview - A web framework that doesn't get in the way, or suck.

NOTICE!

This POD is being rewritten and is probably out-dated. If so please refer to SweetPea for the current documentation, keep in mind that as this module is new and undergoing active development, the documentation is subject to change without notice.

Also Note! The sweetpea application generator script has been moved to SweetPea::Cli and the usage and syntax has changed a bit.

SYNOPSIS

Oh how Sweet web application development can be ...

    # start with a minimalist script
    > sweetpea make --script
    
    use SweetPea;
    sweet->routes({
    
        '/' => sub {
            shift->forward('/way');
        },
        
        '/way' => sub {
            shift->html('I am the way the truth and the light!');
        }
        
    })->run;
    
    # graduate to a ful-fledge application with scalable MVC architecture
    # no refactoring required
    > sweetpea make
    
    use SweetPea;
    sweet->run;
    
    #look mom, auto-routes unless I tell it otherwise.

DESCRIPTION

SweetPea is a modern web application framework that follows the MVC (Model, View, Controller) design pattern using useful concepts from Mojolicious, Catalyst and other robust web frameworks. SweetPea has a short learning curve, is light-weight, as scalable as you need it to be, and requires little configuration.

BASIC INSTALLATION

Oh how Sweet web application development can be ...

    ... using the cli (command line interface)
    
    # download, test and install
    cpan SweetPea
    
    # build your skeleton application
    cd web_server_root/htdocs/my_new_application
    sweetpea make
    

That's all Folks, wait, SweetPea just got Sweeter. SweetPea now supports routes. Checkout this minimalist App.

    ... in .pl
    use SweetPea;
    sweet->routes({
    
        '/' => sub {
            shift->html('I took index.html\'s good, he got lazy.');
        }
        
    })->run;

EXPORTED

    sweet (shortcut to SweetPea object instantiation)

HOW IT WORKS

SweetPea uses a simple MVC pattern and ideology for processing and responding to requests from the users browser. Here is an example request and response outlining how SweetPea behaves when a request is received.

    # The request
    http://localhost/admin/auth/
    - The user requests http://localhost/admin/auth/ from the browser.
    
    # The simple MVC pattern
    http://localhost/(admin/auth/)
    - admin/auth either matches as a Controller or Controller/Action.
    - e.g. Controller::Admin::auth() or Controller::Admin::Auth::_index()
    
    # The response
    - .pl (dispatcher/router) invokes SweetPea->new->run
    - the run method loads all plugins and scans the controllers folder
    building a table of controller/actions for further dispatching.
    - the dispatching routine executes the global or local _begin method,
    then executes the action or global or local _index method, and
    finally executes the global or local _end method.
    - the start and finish methods are then called to create, render
    and finalize the response and output.
    
    # Other magic (not included)
    * SweetPea will support routing which is a very popular way of
    dispatching URLs. Using routes will disable the default method
    of discovering controllers and actions making the application
    more secure. SweetPea will default scanning the controllers
    folder if no routes are defined.

APPLICATION STRUCTURE

    /static                 ## static content (html, css) is stored here
    /sweet                  ## application files are stored here
        /application        ## MVC files are stored here
            /Controller     ## controllers are stored here
                Root.pm     ## default controller (should always exist)
                Sweet.pm    ## new application welcome page controller
            /Model          ## models are stored here
                Schema.pm   ## new application boiler-plate model 
            /View           ## views are stored here
                Main.pm     ## new application boiler-plate view
        /sessions           ## auto-generated session files are stored here
        /templates          ## templates and layouts can be stored here
        App.pm              ## module for loading plugins (other modules)
    /.htaccess              ## enables pretty-urls on apache w/mod-rewrite
    /.pl                    ## default dispatcher (controller/action router)

GENERATED FILES INFORMATION

sweet/application/Controller/Root.pm

Controller::Root

    The Root.pm controller is the default controller similar in function to
    a directory index (e.g. index.html). When a request is received that can
    not be matched in the controller/action table, the root/index
    (or Controller::Root::_index) method is invoked. This makes the _index
    method of Controller::Root, a kind of global fail-safe or fall back
    method.
    
    The _begin method is executed before the requested action, if no action
    is specified in the request the _index method is used, The _end method
    is invoked after the requested action or _index method has been
    executed.
    
    The _begin, _index, and _end methods can exist in any controller and
    serves the same purposes described here. During application request
    processing, these special routines are checked for in the namespace of
    the current requested action's Controller, if they are not found then
    the (global) alternative found in the Controller::Root namespace will
    be used.

    The _startup method is a special global method that cannot be overridden
    and is executed first with each request. The _shutdown is executed last
    and cannot be overridden either.

    # in Controller/Root.pm
    package Controller::Root;
    sub _startup { my ( $self, $s ) = @_; }
    sub _begin { my ( $self, $s ) = @_; }
    sub _index { my ( $self, $s ) = @_; }
    sub _end { my ( $self, $s ) = @_; }
    sub _shutdown { my ( $self, $s ) = @_; }
    1;

sweet/application/Controller/Sweet.pm

Controller::Sweet

    # Sweet.pm
    * A welcome page for the newly created application. (Safe to delete)

sweet/application/Model/Schema.pm

Model::Schema

    # Model/Schema.pm
    The Model::Schema boiler-plate model package is were your data
    connection, accessors, etc can be placed. SweetPea does not impose
    a specific configuration style, please feel free to connect to your
    data in the best possible fashion. Here is an example of how one
    might use this empty package with DBIx::Class.
    
    # in Model/Schema.pm
    package Model::Schema;
    use base qw/DBIx::Class::Schema::Loader/;
    __PACKAGE__->loader_options(debug=>1);
    1;
    
    # in App.pm
    use Model::Schema;
    sub plugins {
        ...
        $s->plug('data', sub { shift; return Model::Schema->new(@_) });
    }
    
    # example usage in Controller/Root.pm
    sub _dbconnect {
        my ($self, $s) = @_;
        $s->data->connect($dbi_dsn, $user, $pass, \%dbi_params);
    }

sweet/application/View/Main.pm

View::Main

    # View/Main.pm
    The View::Main boiler-plate view package is were your layout/template
    accessors and renders might be stored. Each view is in fact a package
    that determines how data should be rendered back to the user in
    response to the request. Examples of different views are as follows:
    
    View::Main - Main view package that renders layouts and templates
    based on the main application's user interface design.
    
    View::Email::HTML - A view package which renders templates to
    be emailed as HTML.
    
    View::Email::TEXT - A view package which renders templates to be
    emailed as plain text.
    
    Here is an example of how one might use this empty
    package with Template (template toolkit).
    
    # in View/Main.pm
    package View::Main;
    use base Template;
    sub new {
        return __PACKAGE__->new({
        INCLUDE_PATH => 'sweet/templates/',
        EVAL_PERL    => 1,
        });
    }
    1;
    
    # in App.pm
    use View::Main;
    sub plugins {
        ...
        $s->plug('view', sub{ shift; return View::Main->new(@_) });
    }
    
    # example usage in Controller/Root.pm
    sub _index {
        my ($self, $s) = @_;
        $s->view->process($input, { s => $s });
    }    
    

sweet/application/App.pm

App

    # App.pm
    The App application package is the developers access point to
    configure and extend the application before request processing. This
    is typically done using the plugins method. This package contains
    the special and required plugins method. Inside the plugins method is
    were other Modules are loaded and Module accessors are created using
    the core "plug" method. The following is an example of App.pm usage.
    
    package App;
    use warnings;
    use strict;
    use HTML::FormFu;
    use HTML::GridFu;
    use Model::Schema;
    use View::Main;
    
    sub plugins {
        my ( $class, $s ) = @_;
        my $self = bless {}, $class;
        $s->plug( 'form', sub { shift; return HTML::FormFu->new(@_) } );
        $s->plug( 'data', sub { shift; return Model::Schema->new(@_) } );
        $s->plug( 'view', sub { shift; return View::Main->new(@_) } );
        $s->plug( 'grid', sub { shift; return HTML::GridFu->new(@_) } );
        return $s;
    }
    1;    # End of App

.htaccess

htaccess

    # .htaccess
    The .htaccess file allows apache-type web servers that support
    mod-rewrite to automatically configure your application environment.
    Using mod-rewrite your application can make use of pretty-urls. The
    requirements for using .htaccess files with your SweetPea application
    are as follows:
    
    mod-rewrite support
    .htaccess support with Allow, Deny
    
    # in .htaccess
    DirectoryIndex .pl
    AddHandler cgi-script .pl .pm .cgi
    Options +ExecCGI +FollowSymLinks -Indexes
    
    RewriteEngine On
    RewriteCond %{SCRIPT_FILENAME} !-d
    RewriteCond %{SCRIPT_FILENAME} !-f
    RewriteRule (.*) .pl/$1 [L]

.pl

pl

    # .pl
    The .pl file is the main application router/dispatcher. It is
    responsible for prepairing the application via executing all pre and
    post processing routines as well as directing requests to the
    appropriate controllers and actions.
    
    #!/usr/env/perl
    BEGIN {
        use FindBin;
        use lib $FindBin::Bin . '/sweet';
        use lib $FindBin::Bin . '/sweet/application';
    }
    use SweetPea;
    use App;
    SweetPea->new->run;

SPECIAL ROUTINES

_startup

    # _startup
    sub _startup {...}
    The _startup method is a special global method that cannot be overridden
    and is executed before any other methods automatically with each request.

_begin

    # _begin
    sub _begin {...}
    
    The begin method can exist both globally and locally, and will be
    automatically invoked per request. When a request is processed,
    SweetPea checks whether the _begin method exists in the namespace
    of the Controller being requested, if not it checks whether the
    _begin method exists in the Controller::Root namespace and
    executes that method. If you opt to keep and use the default
    controller Controller::Root, then its _begin method will be
    defined as the global _begin method and will be executed
    automatically with each request. The automatic execution of
    _begin in Controller::Root can be overridden by adding a _begin
    method to the namespace of the controller to be requested.
    
    This special method is useful for checking user permissions, etc.

_index

    # _index
    sub _index {...}
    
    The index method can exist both globally and locally, and will
    be automatically invoked *only* if an action is not specified.
    When a request is processed, SweetPea scans the controllers
    folder building a table of controllers and actions for
    dispatching. The dispatching routine executes attempts to
    execute the action, if no action is specified, it
    default to executing the global or local _index method
    looking locally first, then globally ofcourse. The automatic
    execution of _index in Controller::Root can be overridden by
    adding a _index method to the namespace of the controller to
    be requested.
    
    This special method acts as a directory index or index.html
    file in that it is executed when no other file (action) is
    specified.
    

_end

    # _end
    sub _end {...}
    
    The end method can exist both globally and locally, and will be
    automatically invoked per request. When a request is processed,
    SweetPea checks whether the _end method exists in the namespace
    of the Controller being requested, if not it checks whether the
    _end method exists in the Controller::Root namespace and
    executes that method. If you opt to keep and use the default
    controller Controller::Root, then its _end method will be
    defined as the global _end method and will be executed
    automatically with each request. The automatic execution of
    _end in Controller::Root can be overridden by adding a _end
    method to the namespace of the controller to be requested.
    
    This special method is useful for performing cleanup
    functions at the end of a request.

_shutdown

    # _shutdown
    sub _shutdown {...}
    The _shutdown method is a special global method that cannot be overridden
    and is executed after all other methods automatically with each request.

RULES AND SYNTAX

The anatomy of a controller method

    Controllers are used by SweetPea in an OO (object-oriented)
    fashion and thus, all controller methods should follow the
    same design as they are passed the same parameters.
    
    package Controller::Foo;
    
    sub bar {
        my ($self, $s) = @_;
        ...
    }
    
    1;
    
    The foo method above (as well as al other controller methods)
    are passed at least two objects, an instance of the current
    controller usually referred to as $self, and an instance of
    the SweetPea application object usually referred to as $s.
    
    Note! Actions prefixed with an underscore can not be
    displatched to using URLs.
    

How to use plugins (other modules)

    Plugins are a great way to extend the functionality of a
    SweetPea application. Plugins are defined in the application
    package App.pm inside of the special plugins method as
    follows:
    
    # inside of App.pm
    package App;
    ...
    use CPAN::Module;
    
    sub plugins {
        ...
        $s->plug( 'cpan', sub { shift; return CPAN::Module->new(@_) } );
        return $s;
    }
    ...
    
    # notice below how an accessor is created for the ficticious
    CPAN::Module in the SweetPea namespace
    
    # inside sweet/Controller/MyController.pm
    sub _index {
        my ($self, $s) = @_;
        $s->cpan->some_method(...);
    }
    
    # when $s->cpan is called, it creates (unless the object reference
    exists) and returns a reference to that module object. To create
    or initialize another object, simply call the unplu method on the
    object's name.
    
    # inside sweet/Controller/MyController.pm
    sub _index {
        my ($self, $s) = @_;
        my $foo = $s->cpan;
        my $bar = $s->cpan;
        my $baz = $s->unplug('cpan')->cpan;
    }
    
    # in the example above, $foo and $bar hold the same reference, but
    $baz is holding a new refernce as if it called CPAN::Module->new;

INSTANTIATION

new

    The new method initializes a new SweetPea object.
    
    # in your .pl or other index/router file
    my $s = SweetPea->new;

run

    The run method discovers
    controllers and actions and executes internal pre and post request processing
    routines.

    # in your .pl or other index/router file
    my $s = SweetPea->new->run; # start processing the request
    
    NOTE! CGI, CGI::Cookie, and CGI::Session are plugged in automatically
    by the run method.
    
    # accessible via $s->cgi, $s->cookie, and $s->session

ROUTING/DISPATCHING

    The routes method like most popular routing mechanisms allows you to map
    urls to routines. SweetPea by default uses an auto-discovery mechanism on
    the controllers folder to create routes automatically, however there are
    times when additional flexibility is required.
    
    There are two types of routes defined when your application is executed,
    auto-routing and manual routing. As stated before, auto-routing
    automatically builds routes base on the Controllers in your applications
    controllers folder (which is created automatically when you "make" an app
    using the sweetpea cli). Manual routing is usually established in the
    dispatcher file as follows:
    
    sweet->routes({
        
        '/' => sub {
            shift->html('Index page much!');
        }
        
    })->new;
    
    SweetPea routing has support for inline URL parameters and wildcard
    operators. See examples below:
    
    sweet->routes({
        
        '/:goto' => sub {
            my $s = shift;
            $s->html('Your trying to get to ' . $s->param('goto') );
            ...
        },
        '/download/*' => sub {
            my $s = shift;
            $s->redirect($s->param('*')) if $s->param('*');
            ...
        },
        '/dl/:file/:from' => sub {
            my $s = shift;
            if ($s->param('file')) {
                my $contents = $s->file('<',
                    $s->param('from') . '/' . $s->param('file');
                );
            }
            ...
        }
        
    })->run;

CONTROLLERS AND ACTIONS

    Controllers are always created in the sweet/controller folder and defined
    under the Controller namespace, e.g. Controller::MyController. In keeping
    with simplicity, controllers and actions are actually packages and
    routines ( controller/action = package controller; sub action {...} ).
    
    NOTE! Actions prefixed with an underscore e.g. _foo can not be dispatched to
    using URLs but are listed in the dispatch table and are available to
    the forward, detach and many other methods that might invoke an
    action/method.

RAD METHODS

RAD (Rapid Application Development) methods assist in the creation of common files, objects and funtionality. These methods reduce the tedium that comes with creating web applications models, views and controllers.

make

    This function is available through the command-line interface.
    This creates the boiler plate appication structure.
    
    # e.g. at the command line
    sweetpea make
    > Created file /sweet/App.pm (chmod 755) ...
    > Created file /.pl (chmod 755) ...
    > Created file /.htaccess (chmod 755) ...
    > Creat....
    > ...

ctrl

    This function is available through the command-line interface.
    This method creates a controller with a boiler plate structure
    and global begin, index, and end methods.
    
    # e.g. at the command line
    sweetpea ctrl admin/auth
    > Created file /sweet/application/Controller/Admin/Auth.pm (chmod 755) ...

model

    This function is available through the command-line interface.
    This method creates a model with a boiler plate structure.
    
    # e.g. at the command line
    sweetpea model csv/upload
    > Created file /sweet/application/Model/Csv/Upload.pm (chmod 755) ...

view

    This function is available through the command-line interface.
    This method creates a view with a boiler plate structure.
    
    # e.g. at the command line
    sweetpea view email/html
    > Created file /sweet/application/View/Email/Html.pm (chmod 755) ...

HELPER METHODS

controller

    The action method returns the current requested MVC
    controller/package.
    
    # user requested http://localhost/admin/auth
    
    $controller = $s->controller
    # $controller is /admin
    
    $controller = $s->controller('services');
    # $controller is /admin/services
    
    # maybe useful for saying
    
    $s->forward( $s->controller('services') );
    # executes Controller::Admin::services()

action

    The action method returns the current requested MVC
    action.
    
    # user requested http://localhost/admin/auth
    
    $action = $s->action
    # $action is auth if auth is an action, blank if not

url/uri

    The url/uri methods returns a completed URI string
    or reference to root, here or path variables, e.g.
    
    # user requested http://localhost/admin/auth
    
    my $link = $s->url('static/index.html');
    # $link is http://localhost/static/index.html
    
    # $s->uri->{root} is http://localhost
    # $s->uri->{here} is http://localhost/admin/auth
    # $s->uri->{path} is /admin/auth

path

    The path method returns a completed path to root
    or location passed to the path method.
    
    # application lives at /domains/sweetapp
    
    my $path = $s->path;
    # $path is /domains/sweetapp
    
    my $path = $s->path('static/index.html');
    # $path is /domains/sweetapp/static/index.html

cookies

    Returns an array of cookies set throughout the request.
    ...
    foreach my $cookie (@{$s->cookies}) {
        # do something with the cookie data
    }

param

    The param methods is an all purpose shortcut to accessing CGI's url_param,
    param (post param method), and CGI::Session's param methods in that order.
    Convenient when all params have unique names.

CONTROL METHODS

start

    The start method should probably be named (startup) because
    it is the method which processes the request and performs
    various startup tasks.
    
    # is invoked automatically

finish

    The finish method performs various tasks in processing the
    response to the request.
    
    # is invoked automatically

forward

    The forward method executes a method in a namespace,
    then continues to execute instructions in the method it was
    called from.
    
    # in Controller::Admin
    sub auth {
        my ($self, $s) = @_;
        $s->forward('/admin/auth_success');
        # now im doing something else
    }
    
    sub auth_success {
        my ($self, $s) = @_;
        # im doing something
    }
    
    using forward to here was inefficient, one could have used
    $self->auth_success($s) because we are in the same package.

detach

    The detach method executes a method in a namespace, then
    immediately executes the special "_end" method which finalizes
    the request.
    
    # in Controller::Admin
    sub auth {
        my ($self, $s) = @_;
        $s->detach('/admin/auth_success');
        # nothing after is executed
    }
    
    sub auth_success {
        my ($self, $s) = @_;
        # im doing something
    }
    
    using forward to here was inefficient, one could have used
    $self->auth_success($s) because we are in the same package.

METHODS

store

    The store method is an accessor to the special "store"
    hashref. The store hashref is the functional equivilent
    of the stash method found in many other frameworks. It
    serves as place developers can save and retreive information
    throughout the request.
    
    $s->store->{important_stuff} = "This is top secret stuff";

application

    The application method is in accessor to the special
    "application" hashref. As the "store" hashref is where general
    application data is stored, the "application" hashref is where
    application configuration information is stored.
    
    $s->application->{content_type} = 'text/html';
    
    This is just an example, to change the content type please use
    $s->content_type('text/html');
    Content-Type is always 'text/html' by default.

content_type

    The content_type method set the desired output format for use
    with http response headers.
    
    $s->content_type('text/html');

request_method

    The request_method return the valu set in the REQUEST_METHOD
    Environment Variable and is generally used as follows:
    
    if ( $s->request_method eq 'get' ) {
        ...
    }
    
    Alternatively, for testing purposes, the request_method method can be
    use to return a boolean true or false based on whether the supplied
    value matches the current value in the REQUEST_METHOD Environment
    Variable.
    
    if ( $s->request('get')) {
        ...
    }

request

    The request method is an alias for request_method.

file

    The file method assists in creating, editing and deleting files on the
    file system without the to need to create and close file handles manually.
    
    $s->file('>', 'somefile.txt', $data);  # write
    $s->file('>>', 'somefile.txt', $data); # append
    $s->file('<', 'somefile.txt');  # read
    $s->file('x', 'somefile.txt');  # delete
    

push_download

    The push_download method when used prompts the user to download the
    specified file without redirect.
    
    $s->push_download('test.txt');

flash

    The flash method provides the ability to pass a single string of data
    from request "A" to request "B", then that data is deleted as to prevent
    it from being passed to any additional requests.
    
    # set flash message
    my $message = $s->flash('This is a test flash message');
    # $message equals 'This is a test flash message'
    
    # get flash message
    my $message = $s->flash();
    # $message equals 'This is a test flash message'
    
    # clear flash message
    my $message = $s->flash('');
    # returns previous message then clears, $message equals ""

html

    The html method sets data to be output to the browser or if
    called with no parameters returns the data recorded and
    clears the data store.
    
    If the html store contains any data at the end of the request,
    it is output to the browser.
    
    # in Controller::Root
    sub _index {
        my ($self, $s) = @_;
        $s->html('this is a test');
        $self->my_two_cents($s);
    }
    
    sub my_two_cents {
        my ($self, $s) = @_;
        $s->html(', or maybe not');
    }
    
    "this is a test, or maybe not" is output to the browser
    
    # in Controller::Root
    
    my @data;
    
    sub _index {
        my ($self, $s) = @_;
        $s->html('this is a test');
        $self->forget_it($s);
    }
    
    sub forget_it {
        my ($self, $s) = @_;
        @data = @{$s->html};
    }
    
    Nothing is output to the browser as $s->html returns and
    array of data stored in it and clears itself
    
    # @data contains ['this is a test','or maybe not']

upload

    The upload method copies a file from the users computer to the server
    with the option of renaming the file.
    
    my $file = $s->upload('input_file_field');
    my $file = $s->upload('input_file_field', 'location');
    my $file = $s->upload('input_file_field', 'location', 'new_file_name');

debug

    The debug method sets data to be output to the browser with
    additional information for debugging purposes or if called
    with no parameters returns the data recorded and clears the
    data store. debug() is the functional equivilent of html()
    but with a different purpose.

output

    This method spits out html or debug information stored using
    $s->html and/or $s->debug methods throughout the request. The
    output method takes one argument, an entry seperator, which
    if defined (empty or not) will output debug data, if not
    explicitly defined will output html data.
    
    $s->output;
    # outputs html data.
    
    $s->output(""); or $s->output("\n"); or $s->output("<br/>");
    # outputs debug data.

redirect

    This method redirects the request to the supplied url. If no url
    is supplied, the request is redirected to the default page as defined
    in your .htaccess or controller/Root.pm file.

plug

    The plugin method creates accessors for third party (non-core)
    modules, e.g.
    
    $self->plug('email', sub{ shift; return Email::Stuff->new(@_) });
    
    # allow you to to say
    # in Controller::Root
    
    sub _index {
        my ($self, $s) = @_;
        $self->email->to(...)->from(...)->etc...
    }
    
    
    # NOTE! plugins should be defined within the plugins methods of
    the App.pm package;

unplug

    The unplug method releases the reference to the module object
    used by the module accessor created by the plug method.
    
    # inside sweet/Controller/MyController.pm
    sub _index {
        my ($self, $s) = @_;
        my $foo = $s->cpan;
        my $bar = $s->cpan;
        my $baz = $s->unplug('cpan')->cpan;
    }
    
    # in the example above, $foo and $bar hold the same reference, but
    $baz is holding a new refernce as if it called CPAN::Module->new;
    as defined in the plugins method in App.pm

routes

    The routes method like most popular routing mechanisms allows you to map
    urls to routines. SweetPea by default uses an auto-discovery mechanism on
    the controllers folder to create routes automatically, however there are
    times when additional flexibility is required. This is where the routes
    method is particularly useful, also the routes method supports inline
    url parameters e.g. http:/localhost/route/param1/param2. The easiest way
    to use the routes method is from within the dispatcher (.pl file).
    
    # ... in the .pl file
    # new
    sweet->routes({
    
        '/:caption' => sub {
            my $s = shift;
            $s->html('Hello World, ' . $s->param('caption'));
        }
        
    })->run;
    
    #old
    SweetPea->new->routes({

        '/:caption' => sub {
            my $s = shift;
            $s->html('Hello World, ' . $s->param('caption'));
        },
        '/:caption/:name' => sub {
            my $s = shift;
            $s->html('Hello World, ' . $s->param('caption') .
            ' my name is ' . $s->param('name')
            );
        }

    })->run;
    
    It is very important to understand the sophisticated routing SweetPea
    performs and how it scales with your application over its lifecycle as
    you add more routes and controllers.
    
    There are two types of routes defined when your application is executed,
    auto-routing and manual routing. As stated before, auto-routing
    automatically builds routes base on the Controllers in your applications
    controllers folder. Manual routing is usually established in the dispatcher
    file as outlined above. Manually created routes take priority over
    automatically generated ones, so if an automatically generated route exists
    that occupies the path of a manually defined one, the manually create one
    will be override the automatically created one.