NAME

Kelp - A web framework light, yet rich in nutrients.

SYNOPSIS

package MyApp;
use parent 'Kelp';

# bootstrap your application
sub build {
    my ($self) = @_;

    my $r = $self->routes;

    $r->add('/simple/route', 'route_handler');
    $r->add('/route/:name', {
        to => 'namespace::controller::action',
        ... # other options, see Kelp::Routes
    });
}

# example route handler
sub route_handler {
    my ($kelp_instance, @route_parameters) = @_;

    return 'text to be rendered';
}

1;

DESCRIPTION

Kelp is a light, modular web framework built on top of Plack.

This document lists all the methods and attributes available in the main instance of a Kelp application, passed as a first argument to route handling routines. If you're just getting started, you may be more interested in the following documentation pages:

See Kelp::Manual for a complete reference.

See Kelp::Manual::Cookbook for solutions to common problems.

REASONS TO USE KELP

  • Plack ecosystem. Kelp isn't just compatible with Plack, it's built on top of it. Your application can be supported by a collection of already available Plack components.

  • Advanced Routing. Create intricate, yet simple ways to capture HTTP requests and route them to their designated code. Use explicit and optional named placeholders, wildcards, or just regular expressions.

  • Flexible Configuration. Use different configuration file for each environment, e.g. development, deployment, etc. Merge a temporary configuration into your current one for testing and debugging purposes.

  • Enhanced Logging. Log messages at different levels of emergency. Log to a file, screen, or anything supported by Log::Dispatch.

  • Powerful Rendering. Use the built-in auto-rendering logic, or the template module of your choice to return rich text, html and JSON responses.

  • JSON encoder/decoder. Kelp can handle JSON-formatted requests and responses automatically, making working with JSON much more enjoyable. On top of that, it uses JSON::MaybeXS to choose the best (fastest, most secure) backend available.

  • Extendable Core. Kelp has straightforward code and uses pluggable modules for everything. This allows anyone to extend it or add a module for a custom interface. Writing Kelp modules is easy.

  • Sleek Testing. Kelp takes Plack::Test and wraps it in an object oriented class of convenience methods. Testing is done via sending requests to your routes, then analyzing the response.

ATTRIBUTES

host

Gets the current hostname.

sub some_route {
    my $self = shift;
    if ( $self->host eq 'prod-host' ) {
        ...
    }
}

mode

Sets or gets the current mode. The mode is important for the app to know what configuration file to merge into the main configuration. See Kelp::Module::Config for more information.

my $app = MyApp->new( mode => 'development' );
# conf/config.pl and conf/development.pl are merged with priority
# given to the second one.

context_obj

Provide a custom package name to define the ::Context object. Defaults to Kelp::Context.

middleware_obj

Provide a custom package name to define the middleware object. Defaults to Kelp::Middleware.

request_obj

Provide a custom package name to define the ::Request object. Defaults to Kelp::Request.

response_obj

Provide a custom package name to define the ::Response object. Defaults to Kelp::Response.

config_module

Sets of gets the class of the configuration module to be loaded on startup. The default value is Config, which will cause the Kelp::Module::Config to get loaded. See the documentation for Kelp::Module::Config for more information and for an example of how to create and use other config modules.

loaded_modules

A hashref containing the names and instances of all loaded modules. For example, if you have these two modules loaded: Template and JSON, then a dump of the loaded_modules hash will look like this:

{
    Template => Kelp::Module::Template=HASH(0x208f6e8),
    JSON     => Kelp::Module::JSON=HASH(0x209d454)
}

This can come in handy if your module does more than just registering a new method into the application. Then, you can use its object instance to access that additional functionality.

path

Gets the current path of the application. That would be the path to app.psgi

name

Gets or sets the name of the application. If not set, the name of the main class will be used.

my $app = MyApp->new( name => 'Twittar' );

charset

Gets or sets the output encoding charset of the app. It will be UTF-8, if not set to anything else. The charset can also changed in the config files.

If the charset is explicitly configured to be undef or false, the application won't do any automatic encoding of responses, unless you set it by explicitly calling "charset" in Kelp::Response.

request_charset

Same as "charset", but only applies to the input. Request data will be decoded using this charset or charset which came with the request.

If the request charset is explicitly configured to be undef or false, the application won't do any automatic decoding of requests, even if message came with a charset.

For details, see "ENCODING" in Kelp::Request.

long_error

When a route dies, Kelp will by default display a short error message. Set this attribute to a true value if you need to see a full stack trace of the error. The KELP_LONG_ERROR environment variable can also set this attribute.

req

This attribute only makes sense if called within a route definition. It will contain a reference to the current Kelp::Request instance.

sub some_route {
    my $self = shift;
    if ( $self->req->is_json ) {
        ...
    }
}

This attribute is a proxy to the same attribute in "context".

res

This attribute only makes sense if called within a route definition. It will contain a reference to the current Kelp::Response instance.

sub some_route {
    my $self = shift;
    $self->res->json->render( { success => 1 } );
}

This attribute is a proxy to the same attribute in "context".

context

This holds application's context. Its usage is advanced and only useful for controller logic, but may allow for some introspection into Kelp.

For example, if you have a route in a controller and need to get the original Kelp app object, you may call this:

sub some_route {
    my $controller = shift;
    my $app = $controller->context->app;
}

encoder_modules

A hash reference of registered encoder modules. Should only be interacted with through "get_encoder" or inside encoder module's code.

METHODS

new

my $the_only_kelp = KelpApp->new;

A standard constructor. Cannot be called multiple times: see "new_anon".

new_anon

my $kelp1 = KelpApp->new_anon(config => 'conf1');
my $kelp2 = KelpApp->new_anon(config => 'conf2');

Deprecated. This only solves the problem in a basic scenario and has a critical bug when it comes to subclassing and reblessing the app. The new_anon constructor itself will not be removed, but its internals will be modified to use a more robust implementation method. It is not guaranteed to work exactly the same for your use case with the new method. It's usually better to treat every Kelp app like a singleton since that's how it was designed.

A constructor that can be called repeatedly. Cannot be mixed with "new".

It works by creating a new anonymous class extending the class of your application and running new on it. ref $kelp will return something else than the name of your Kelp class, but $kelp->isa('KelpApp') will be true. This will likely be useful during testing or when running multiple instances of the same application with different configurations.

build

On its own, the build method doesn't do anything. It is called by the constructor, so it can be overridden to add route destinations and initializations.

package MyApp;

sub build {
    my $self = shift;
    my $r = $self->routes;

    # Load some modules
    $self->load_module("MongoDB");
    $self->load_module("Validate");

    # Add all route destinations
    $r->add("/one", "one");
    ...

}

load_module

load_module($name, %options)

Used to load a module. All modules should be under the Kelp::Module:: namespace. If they are not, their class name must be prepended with +.

$self->load_module("Redis", server => '127.0.0.1');
# Will look for and load Kelp::Module::Redis

Options for the module may be specified after its name, or in the modules_init hash in the config. Precedence is given to the inline options. See Kelp::Module for more information on making and using modules.

build_context

This method is used to build the context. By default, it's used lazily by "context_obj" attribute. It can be overridden to modify how context is built.

build_request

This method is used to create the request object for each HTTP request. It returns an instance of the class defined in the request_obj attribute (defaults to Kelp::Request), initialized with the current request's environment. You can override this method to use a custom request module if you need to do something interesting. Though there is a provided attribute that can be used to overide the class of the object used.

package MyApp;
use MyApp::Request;

sub build_request {
    my ( $self, $env ) = @_;
    return MyApp::Request->new( app => $app, env => $env );
}

# Now each request will be handled by MyApp::Request

build_response

This method creates the response object, e.g. what an HTTP request will return. By default the object created is Kelp::Response though this can be overwritten via the respone_obj attribute. Much like "build_request", the response can also be overridden to use a custom response object if you need something completely custom.

before_dispatch

Override this method to modify the behavior before a route is handled. The default behavior is to log access (if logger is available).

package MyApp;

sub before_dispatch {
    my ( $self, $destination ) = @_;

    # default access logging is disabled
}

The $destination param will depend on the routes implementation used. The default router will pass the unchanged "to" in Kelp::Routes::Pattern. If possible, it will be run on the controller object (allowing overriding before_dispatch on controller classes).

after_unrendered

Override this method to control what's going to happen when a route has been found but it did not render anything. The default behavior is to render page 404 (if only bridges are found) or throw an error.

This hook will get passed an array reference to all matched routes, so you can inspect them at will to decide what to do. It's strongly recommended to still render 404 if the last match is a bridge (as is default).

sub after_unrendered {
    my ( $self, $matches ) = @_;

    if ($matches->[-1]->bridge) {
        $self->res->render_404;
    }
    else {
        # do something custom
    }
}

before_finalize

Override this method to modify the response object just before it gets finalized.

package MyApp;

sub before_finalize {
    my $self = shift;
    $self->res->set_header("X-App-Name", "MyApp");
}

...

The above is an example of how to insert a custom header into the response of every route.

run

This method builds and returns the PSGI app. You can override it to get more control over PSGI representation of the app.

param

A shortcut to $self->req->param:

sub some_route {
    my $self = shift;
    if ( $self->param('age') > 18 ) {
        $self->can_watch_south_path(1);
    }
}

This function can be tricky to use because of context sensivity. See "param" in Kelp::Request for more information and examples.

session

A shortcut to $self->req->session. Take a look at "session" in Kelp::Request for more information and examples.

stash

Provides safe access to $self->req->stash. When called without arguments, it will return the stash hash. If called with a single argument, it will return the value of the corresponding key in the stash. See "stash" in Kelp::Request for more information and examples.

named

Provides safe access to $self->req->named. When called without arguments, it will return the named hash. If called with a single argument, it will return the value of the corresponding key in the named hash. See "named" in Kelp::Request for more information and examples.

url_for

A safe shortcut to $self->routes->url. Builds a URL from path and arguments.

sub build {
    my $self = shift;
    $self->routes->add("/:name/:id", { name => 'name', to => sub {
        ...
    }});
}

sub check {
    my $self = shift;
    my $url_for_name = $self->url_for('name', name => 'jake', id => 1003);
    $self->res->redirect_to( $url_for_name );
}

abs_url

Same as "url_for", but returns the full absolute URI for the current application (based on configuration).

is_production

Returns whether the application is in production mode. Checks if "mode" is either deployment or production.

get_encoder

my $json_encoder = $self->get_encoder('json');

Gets an instance of a given encoder. It takes two arguments:

  • type of the encoder module (eg. json)

  • optional name of the encoder (default is default)

It will get extra config (if available) from encoders.TYPE.NAME configuration hash. Will instantiate the encoder just once and then reuse it. Croaks when there is no such encoder type.

Example new JSON encoder type defined in config:

encoders => {
    json => {
        not_very_pretty => {
            pretty => 0,
        },
    },
},

NEXT_APP

Helper method for giving Kelp back the control over PSGI application. It must be used when declaring route-level middleware. It is context-independent and can be called from Kelp package.

use Plack::Builder;

builder {
    enable 'SomeMiddleware';
    Kelp->NEXT_APP;
}

Internally, it uses kelp.execution_chain PSGI environment to dynamically construct a wrapped PSGI app without too much overhead.

AUTHOR

Stefan Geneshky - minimal <at> cpan.org

LICENSE

This module and all the modules in this package are governed by the same license as Perl itself.