NAME
Kelp::Response - Format an HTTP response
SYNOPSIS
Examples of how to use this module make a lot more sense when shown inside route definitions. Note that in the below examples $self->res
is an instance of Kelp::Response
:
# Render simple text
sub text {
my $self = shift;
$self->res->text->render("It works!");
}
# Render advanced HTML
sub html {
my $self = shift;
$self->res->html->render("<h1>It works!</h1>");
}
# Render a mysterious JSON structure
sub json {
my $self = shift;
$self->res->json->render({ why => 'no' });
}
# Render the stock 404
sub missing {
my $self = shift;
$self->res->render_404;
}
# Render a template
sub view {
my $self = shift;
$self->res->template('view.tt', { name => 'Rick James' } );
}
DESCRIPTION
The PSGI specification requires that each route returns an array with status code, headers and body. Plack::Response
already provides many useful methods that deal with that. This module extends Plack::Response
to add the tools we need to write graceful PSGI compliant responses. Some methods return $self
, which makes them easy to chain.
ATTRIBUTES
rendered
Tells if the response has been rendered. This attribute is used internally and unless you know what you're doing, we recommend that you do not use it.
partial
Sets partial response. If this attribute is set to a true value, it will cause finalize
to return the HTTP status code and headers, but not the body. This is convenient if you intend to stream your content. In the following example, we set partial
to 1 and use finalize
to get a writer
object for streaming.
sub stream {
my $self = shift;
return sub {
my $responder = shift;
# Stream JSON
$self->res->set_code(200)->json->partial(1);
# finalize will now return only the status code and headers
my $writer = $responder->( $self->res->finalize );
# Stream JSON body using the writer object
for ( 1 .. 30 ) {
$writer->write(qq|{"id":$_}\n|);
sleep 1;
}
# Close the writer
$writer->close;
};
}
For more information on how to stream, see the "Delayed-Response-and-Streaming-Body" in PSGI docs.
METHODS
render
This method tries to act smart, without being a control freak. It will fill out the blanks, unless they were previously filled out by someone else. Here is what is does:
If the response code was not previously set, this method will set it to 200.
If no content-type is previously set,
render
will set is based on the type of the data rendered. If it's a reference, then the content-type will be set toapplication/json
, otherwise it will be set totext/html
.# Will set the content-type to json $res->render( { numbers => [ 1, 2, 3 ] } );
Last, the data will be encoded with the charset specified by the app.
set_content_type
Sets the content type of the response and returns $self
.
# Inside a route definition
$self->res->set_content_type('image/png');
set_charset
$self->res->json->set_charset;
$self->res->text->set_charset('UTF-16');
Sets the charset inside the content type header to a given value. If the value is not given, sets it to application's charset.
Returns $self
.
WARNING: setting a custom charset means you will have to use "render_binary", as using "render" will still encode to application's charset.
text, html, json, xml
These methods are shortcuts for set_content_type
with the corresponding type. All of them set the content-type header and return $self
so they can be chained.
$self->res->text->render("word");
$self->res->html->render("<p>word</p>");
$self->res->json->render({ word => \1 });
NOTE: text
and html
will also call "set_charset".
set_header
Sets response headers. This is a wrapper around "header" in Plack::Response, which returns $self
to allow for chaining.
$self->res->set_header('X-Something' => 'Value')->text->render("Hello");
no_cache
A convenience method that sets several response headers instructing most browsers to not cache the response.
$self->res->no_cache->json->render({ epoch => time });
The above response will contain headers that disable caching.
set_code
Set the response code.
$self->res->set_code(401)->render("Access denied");
render_binary
Render binary data such as byte streams, files, images, etc. You must explicitly set the content_type before that.
use Kelp::Less;
get '/image/:name' => sub {
my $content = Path::Tiny::path("$name.jpg")->slurp_raw;
res->set_content_type('image/jpeg')->render_binary( $content );
# the same, but probably more effective way (PSGI-server dependent)
open( my $handle, "<:raw", "$name.png" )
or die("cannot open $name: $!");
res->set_content_type('image/png')->render_binary( $handle );
};
render_error
render_error( $code, $error )
Renders the specified return code and an error message. This sub will first look for this error template error/$code
, before displaying a plain page with the error text.
$self->res->render_error(510, "Not Extended");
The above code will look for a template named views/errors/510.tt
, and if not found it will render this message:
510 - Not Extended
A return code of 510 will also be set.
If a standard error message is to be used, it may be skipped - will be pulled from HTTP::Status.
render_404
A convenience method that sets code 404 and returns "File Not Found".
sub some_route {
if ( not $self->req->param('ok') ) {
return $self->res->render_404;
}
}
If your application's tone is overly friendly or humorous, you will want to create a custom 404 page. The best way to do this is to design your own 404.tt template and put it in the views/error folder.
render_500
render_500($optional_error)
Renders the stock "500 - Server Error" message. Designing your own 500 page is also possible. All you need to do is add file 500.tt in views/error. Keep in mind that it will only show in deployment
. In any other mode, this method will display the optional error, or the stock error message.
redirect_to
Redirects the client to a named route or to a given url. In case the route is passed by name, a hash reference with the needed arguments can be passed after the route's name. As a third optional argument, you can enter the desired response code:
$self->redirect_to( '/example' );
$self->redirect_to( 'catalogue' );
$self->redirect_to( 'catalogue', { id => 243 });
$self->redirect_to( 'other', {}, 303 );
template
This method renders a template. The template should be previously configured by you and included via a module. See Kelp::Module::Template for a template module.
sub some_route {
my $self = shift;
$self->res->template('home.tt', { login => 'user' });
}