Kelp

 view release on metacpan or  search on metacpan

lib/Kelp/Manual.pod  view on Meta::CPAN

up to you to use Moose, another object manager, or no object manager at all.
The above example will be just as successful if you used our own little
L<Kelp::Base>:

    package MyApp;
    use Kelp::Base 'Kelp';

    attr dbi => sub {
        ...
    };

    1;

=head1 FRAMEWORK BASICS

=head2 Routing

Kelp uses a powerful and very flexible router. Traditionally, it is also light
and consists of less than 400 lines of code (comments included). You are
encouraged to read L<Kelp::Routes>, but here are some key points. All examples
are assumed to be inside the L<Kelp/build> method and C<$r> is equal to
C<$self-E<gt>routes>:

=head3 Destinations

You can direct HTTP paths to subroutines in your classes or, you can use inline
code.

    $r->add( "/home", "home" );  # goes to sub home
    $r->add( "/legal", "Legal::view" ); # goes to MyApp::Legal::view
    $r->add( "/about", sub { "Content for about" }); # inline

=head3 Restrict HTTP methods

Make a route only catch a specific HTTP method:

    $r->add( [ POST => '/update' ], "update_user" );

=head3 Nesting Plack apps

It's easy to have a Plack app nested in Kelp:

    $r->add( '/app', {
        to => $plack_app->to_app,
        psgi => 1,
    });

See L<Kelp::Routes/PLACK APPS> for details.

=head3 Named captures

Using regular expressions is so Perl. Sometimes, however, it gets a little
overwhelming. Use named paths if you anticipate that you or someone else will
ever want to maintain your code.

=head4 Explicit

    $r->add( "/update/:id", "update" );

    # Later
    sub update {
        my ( $self, $id ) = @_;
        # Do something with $id
    }

=head4 Optional

    $r->add( "/person/?name", sub {
        my ( $self, $name ) = @_;
        return "I am " . $name // "nobody";
    });

This will handle C</person>, C</person/> and C</person/jack>.

=head4 Wildcards

    $r->add( '/*article/:id', 'Articles::view' );

This will handle C</bar/foo/baz/500> and send it to C<MyApp::Articles::view>
with parameters C<$article> equal to C<bar/foo/baz> and C<$id> equal to 500.

Wildcards can also be used without a label:

    # FIXME: will match both /actions/create and /actions_and_stuff
    $r->add( '/actions*' => sub { ... } );

NOTE: matched contents from an unlabelled wildcard will be B<discarded> if your
route also contains named placeholders. Name it to prevent that from happening.

=head4 Slurpy

    $r->add( '/other-app/>rest' => sub {
        my ( $self, $rest ) = @_;
        return "other-app called with path: " . ($rest // '<none>');
    } );

This is a mix of L</Wildcards> and L</Optional>. It works like optional
placeholders but will by default also match slashes.

The use case of this is to have something that hijacks all possibilities under
that path, but also matches for that base path, for example the above will
match all of these:

    /other-app/>rest matches:
        /other-app
        /other-app/
        /other-app/home
        /other-app/article/1

    /other-app/*rest matches:
        /other-app/home
        /other-app/article/1

    /other-app/?rest matches:
        /other-app
        /other-app/
        /other-app/home

Just like wildcards, slurpy placeholders can be used without a label:

    # all user actions and their index in one route



( run in 1.802 second using v1.01-cache-2.11-cpan-a49fcb8fa48 )