Chouette

 view release on metacpan or  search on metacpan

lib/Chouette.pm  view on Meta::CPAN




=head1 CONTEXT OBJECT

For every request a C<Chouette::Context> object is created. This object is passed into the handler for the request. Typically we name the object C<$c>. Your code interacts with the request via the following methods on the context object:

=over

=item C<respond>

The respond method sends a JSON response, the contents of which are encoded from the first argument:

    $c->respond({ a => 1, b => 2, });

Note: After responding, this method returns and your code continues. This is useful if you wish to do additional work after sending the response. However, if you call C<respond> on this context again an error will logged. The second response will not...

If you wish to stop processing after sending the response, you can C<die> with the result from C<respond> since it returns a special object for this purpose:

    die $c->respond({ a => 1, });

See the L<EXCEPTIONS> section for more details on the use of exceptions in Chouette.

C<respond> takes an optional second argument which is the HTTP response code (defaults to 200):

    $c->respond({ error => "access denied" }, 403);

Note that processing continues here also. If you wish to terminate the processing right away, prefix with C<die> as above, or use the following shortcut:

    die "403: access denied";

The client will receive an HTTP response with the L<Feersum> default message ("Forbidden" in this case) and the JSON body will be C<{"error":"access denied"}>.

This works too, except the value of C<error> in the JSON body of the response will just be "HTTP code 403":

    die 403;

=item C<done>

If you wish to stop processing but not send a response:

    $c->done;

You will need to send a response later, usually from an async callback. Note: If the last reference to the context is destroyed without a response being sent, the message C<no response was sent, sending 500> will be logged and a 500 "internal server ...

You don't ever need to call C<done>. You can just C<return> from the handler instead. C<done> is only for convenience in case you are deeply nested in callbacks and don't want to worry about writing a bunch of nested returns.

=item C<respond_raw>

Similar to C<respond> except it doesn't assume JSON encoding:

    $c->respond_raw(200, 'text/plain', 'here is some plain text');

=item C<logger>

Returns the L<Log::Defer> object associated with the request:

    $c->logger->info("some stuff is happening");

    {
        my $timer = $c->logger->timer('doing big_computation');
        big_computation();
    }

See the L<Log::Defer> docs for more details. For viewing the log messages, check out L<Log::Defer::Viz>.

=item C<config>

Returns the C<config> hash. See the L<CHOUETTE OBJECT> section for details.

=item C<req>

Returns the L<Plack::Request> object created for this request.

    my $name = $c->req->parameters->{name};

=item C<res>

One would think this would return a L<Plack::Response> object. Unfortunately this isn't yet implemented and will instead throw an error.

=item C<generate_token>

Generates a random string using a default-config L<Session::Token> generator. The generator is created when the first token is needed so as to avoid a "cold" entropy pool immediately after a reboot (see the L<Session::Token> docs).

=item C<task>

Returns an L<AnyEvent::Task> checkout object for the task with the given name:

    $c->task('db')->selectrow_hashref(q{ SELECT * FROM sometable WHERE id = ? },
                                      undef, $id, sub {
        my ($dbh, $row) = @_;

        die $c->respond($row);
    });

Checkout options can be passed after the task name:

    $c->task('db', timeout => 5)->selectrow_hashref(...);

See L<AnyEvent::Task> for more details.

=back



=head1 EXCEPTIONS

Assuming you are familiar with asynchronous programming, most of L<Chouette> should feel straightforward. The only thing that might be unfamiliar is how exceptions are used.

=head2 ERROR HANDLING

The first unusual thing about how Chouette uses exceptions is that it uses them for error conditions, in contrast to many other asynchronous frameworks.

Most asynchronous frameworks are unable to use exceptions to signal errors since an error may occur in a callback being run from the event loop. If this callback throws an exception, there will be nothing to catch it, except perhaps a catch block ins...

Consider the L<AnyEvent::DBI> library. This is how its error handling works:

    $dbh->exec("SELECT * FROM no_such_table", sub {
        my ($dbh, $rows, $rv) = @_;

        if ($#_) {



( run in 2.043 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )