NAME
Hypersonic::Response - Fluent response builder for Hypersonic
SYNOPSIS
use Hypersonic;
use Hypersonic::Response 'res';
my $server = Hypersonic->new();
# Using the res() shortcut
$server->get('/users/:id' => sub {
my ($req) = @_;
my $id = $req->param('id');
return res->json({ id => $id, name => "User $id" });
});
# Full fluent API
$server->post('/users' => sub {
my ($req) = @_;
my $data = $req->json;
return res
->status(201)
->header('X-Request-Id', 'abc123')
->json({ created => $data->{name} })
->cookie('session', 'token123', httponly => 1, secure => 1);
}, { parse_json => 1 });
# Error responses
$server->get('/admin/:id' => sub {
my ($req) = @_;
my $token = $req->header('Authorization');
return res->unauthorized('Invalid token') unless $token;
return res->not_found('User not found') unless $user;
return res->json($user);
});
# Redirect
$server->get('/old-path' => sub {
return res->redirect('/new-path', 301);
}, { dynamic => 1 });
# Explicit finalize() (usually not needed)
$server->get('/explicit' => sub {
my ($req) = @_;
return res->json({ ok => 1 })->finalize;
}, { dynamic => 1 });
DESCRIPTION
Hypersonic::Response provides a fluent (chainable) API for building HTTP responses. All methods return $self to enable chaining.
The response object uses JIT-compiled array-based storage for maximum performance, similar to Hypersonic::Request.
EXPORTS
res
use Hypersonic::Response 'res';
return res->json({ data => 'value' });
Shortcut constructor for cleaner handler code. Equivalent to Hypersonic::Response->new().
CONSTRUCTOR
new
my $res = Hypersonic::Response->new();
my $res = Hypersonic::Response->new(
status => 201,
headers => { 'X-Custom' => 'value' },
body => 'Hello',
);
Create a new Response object. All options are optional:
- status
-
Initial HTTP status code (default: 200)
- headers
-
Initial headers hashref
- body
-
Initial response body
- cache_dir
-
Directory for JIT compilation cache
METHODS
All setter methods return $self for chaining.
status
$res->status(201);
$res->status(404);
Set the HTTP status code.
header
$res->header('Content-Type', 'application/json');
$res->header('X-Request-Id', $id);
Set a single response header.
headers
$res->headers(
'X-Request-Id' => $id,
'X-Custom' => 'value',
);
Set multiple headers at once.
body
$res->body('Hello, World!');
$res->body($html_content);
Set the response body.
json
$res->json({ status => 'ok', data => $data });
$res->json([ 1, 2, 3 ]);
Set JSON response. Automatically:
Sets Content-Type to
application/jsonEncodes the data structure to JSON
Requires JSON::XS.
text
$res->text('Plain text content');
Set plain text response (Content-Type: text/plain).
html
$res->html('<h1>Hello</h1>');
Set HTML response (Content-Type: text/html).
xml
$res->xml('<root><item/></root>');
Set XML response (Content-Type: application/xml).
content_type
$res->content_type('image/png');
Set the Content-Type header directly.
redirect
$res->redirect('/new-location'); # 302 Found
$res->redirect('/new-location', 301); # 301 Moved Permanently
$res->redirect('/new-location', 307); # 307 Temporary Redirect
Set redirect response with Location header.
cookie
$res->cookie('session', $token);
$res->cookie('session', $token,
path => '/',
domain => '.example.com',
max_age => 3600, # Seconds
expires => $http_date, # HTTP date string
httponly => 1, # Not accessible via JavaScript
secure => 1, # HTTPS only
samesite => 'Strict', # Strict, Lax, or None
);
Set a cookie with optional attributes.
clear_cookie
$res->clear_cookie('session');
$res->clear_cookie('session', path => '/');
Clear a cookie by setting it to expire immediately.
cache
$res->cache('public, max-age=3600');
Set the Cache-Control header.
no_cache
$res->no_cache;
Disable caching with appropriate headers.
etag
$res->etag($checksum);
Set the ETag header.
last_modified
$res->last_modified($timestamp); # Unix timestamp
$res->last_modified(time());
Set the Last-Modified header (auto-formats to HTTP date).
attachment
$res->attachment('report.pdf');
Set Content-Disposition for file download.
CONVENIENCE METHODS
These set both status code and body for common responses:
created
$res->created('/users/42'); # 201 with Location header
no_content
$res->no_content; # 204 No Content
bad_request
$res->bad_request; # 400
$res->bad_request('Invalid input'); # 400 with message
unauthorized
$res->unauthorized; # 401
$res->unauthorized('Invalid token'); # 401 with message
forbidden
$res->forbidden; # 403
$res->forbidden('Access denied'); # 403 with message
not_found
$res->not_found; # 404
$res->not_found('User not found'); # 404 with message
conflict
$res->conflict; # 409
$res->conflict('Already exists'); # 409 with message
unprocessable
$res->unprocessable; # 422
$res->unprocessable('Validation failed');
too_many_requests
$res->too_many_requests; # 429
$res->too_many_requests(60); # With Retry-After header
server_error
$res->server_error; # 500
$res->server_error('Database error'); # 500 with message
unavailable
$res->unavailable; # 503
$res->unavailable(300); # With Retry-After header
FINALIZATION
finalize
my $hashref = $res->finalize;
Convert the Response object to a hashref for returning from handlers. Returns:
{
status => 200,
headers => { 'Content-Type' => 'application/json', ... },
body => '{"data":"value"}',
}
Note: Hypersonic automatically calls finalize() when a Response object is returned, so explicit finalization is usually not needed.
INTERNAL STRUCTURE
The response uses array-based storage:
use Hypersonic::Response qw(SLOT_STATUS SLOT_HEADERS SLOT_BODY SLOT_COOKIES);
# Direct slot access (advanced)
$res->[SLOT_STATUS] = 200;
$res->[SLOT_BODY] = 'content';
EXAMPLES
REST API Response
$server->post('/api/users' => sub {
my ($req) = @_;
my $data = $req->json;
# Validation
return res->bad_request('Name required')
unless $data->{name};
# Create user
my $user = create_user($data);
return res
->status(201)
->header('Location', "/api/users/$user->{id}")
->json($user);
}, { parse_json => 1 });
Conditional Response
$server->get('/api/resource/:id' => sub {
my ($req) = @_;
my $resource = get_resource($req->param('id'));
return res->not_found unless $resource;
return res
->etag($resource->{version})
->cache('private, max-age=60')
->json($resource);
});
File Download
$server->get('/download/:file' => sub {
my ($req) = @_;
my $file = $req->param('file');
my $content = read_file($file);
return res
->content_type('application/octet-stream')
->attachment($file)
->body($content);
});
SEE ALSO
Hypersonic - Main HTTP server module
Hypersonic::Request - JIT-compiled request object
JSON::XS - Required for JSON responses
AUTHOR
LNATION <email@lnation.org>
LICENSE
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.