NAME
MVC::Neaf::Route::Main - main application class for Not Even A Framework.
DESCRIPTION
This class contains a MVC::Neaf application structure and implements the core of Neaf logic.
It is a MVC::Neaf::Route object itself, containing a hash of other routes designated by their path prefixes.
APPLICATION SETUP METHODS
new()
new( )
This is also called by MVC::Neaf->new
, in case one wants to instantiate a Neaf application object instead of using the default "neaf" in MVC::Neaf.
A hash of %options may be added in the future, but isn't supported currently.
add_route()
Define a handler for given by URI path and HTTP method(s). This is the backend behind NEAF's get + post
route specifications.
route( '/path' => CODEREF, %options )
Any incoming request to uri matching /path
(/path/something/else
too, but NOT /pathology
) will now be directed to CODEREF.
Longer paths are GUARANTEED to be checked first.
Dies if the same method and path combination is given twice (but see tentative
and override
below). Multiple methods may be given for the same path.
Exactly one leading slash will be prepended no matter what you do. (path
, /path
and /////path
are all the same).
The CODEREF
MUST accept exactly one argument, referred to as $request
or $req
hereafter, and return an unblessed hashref with response data.
%options may include:
method
- list of allowed HTTP methods. Default is [GET, POST]. Multiple handles can be defined for the same path, provided that methods do not intersect. HEAD method is automatically handled if GET is present, however, one MAY define a separate HEAD handler explicitly.path_info_regex
=>qr/.../
- allow URI subpaths to be handled by this handler.A 404 error will be generated unless
path_info_regex
is present and PATH_INFO matches the regex (without the leading slashes).If path_info_regex matches, it will be available in the controller as
$req->path_info
.If capture groups are present in said regular expression, their content will also be available as
$req->path_info_split
.[EXPERIMENTAL] Name and semantics MAY change in the future.
param_regex
=> { name =>qr/.../
, name2 =>'\d+'
}Add predefined regular expression validation to certain request parameters, so that they can be queried by name only. See
param()
in MVC::Neaf::Request.[EXPERIMENTAL] Name and semantics MAY change in the future.
strict => 1|0
If true, request's
param()
andget_cookie()
will emit HTTP error 422 whenever mandatory validation fails.If parameter or cookie is missing, just return default. This MAY change in the future.
[EXPERIMENTAL] Name and meaning MAY change in the future.
view
- default View object for this Controller. Must be a name of preloaded view, an object with arender
method, or a CODEREF receiving hashref and returning a list of two scalars (content and content-type).[DEPRECATED] Use
-view
instead, meaning is exactly the same.cache_ttl
- if set, set Expires: HTTP header accordingly.[EXPERIMENTAL] Name and semantics MAY change in the future.
default
- a\%hash
of values that will be added to results EVERY time the handler returns. Consider usingneaf default ...
below if you need to append the same values to multiple paths.override
=> 1 - replace old route even if it exists. If not set, route collisions causes exception. Use this if you know better.This still issues a warning.
[EXPERIMENTAL] Name and meaning may change in the future.
tentative
=> 1 - if route is already defined, do nothing. If not, allow to redefine it later.[EXPERIMENTAL] Name and meaning may change in the future.
description
- just for information, has no action on execution. This will be displayed if application called with --list (see MVC::Neaf::CLI).public
=> 0|1 - a flag just for information. In theory, public endpoints should be searchable from the outside while non-public ones should only be reachable from other parts of application. This is not enforced whatsoever.
Also, any number of dash-prefixed keys MAY be present. This is the same as putting them into default
hash.
static()
$neaf->static( '/path' => $local_path, %options );
$neaf->static( '/other/path' => [ "content", "content-type" ] );
Serve static content located under $file_path
. Both directories and single files may be added.
If an arrayref of [ $content, $content_type ]
is given as second argument, serve content from memory instead.
%options may include:
buffer
=>nnn
- buffer size for reading/writing files. Default is 4096. Smaller values may be set, but are NOT recommended.cache_ttl
=>nnn
- if given, files below the buffer size will be stored in memory forcache_ttl
seconds.[EXPERIMENTAL] Cache API is not yet established.
allow_dots => 1|0 - if true, serve files/directories starting with a dot (.git etc), otherwise give a 404.
[EXPERIMENTAL]
dir_index => 1|0 - if true, generate index for a directory; otherwise a 404 is returned, and deliberately so, for security reasons.
[EXPERIMENTAL]
dir_template - specify template for directory listing (with images etc). A sane default is provided.
[EXPERIMENTAL]
view - specify view object for rendering directory template. By default a localized
TT
instance is used.[EXPERIMENTAL] Name MAY be changed (dir_view etc).
override - override the route that was here before. See
route
above.tentative - don't complain if replaced later.
description - comment. The default is "Static content at $directory"
public => 0|1 - a flag just for information. In theory, public endpoints should be searchable from the outside while non-public ones should only be reachable from other parts of application. This is not enforced whatsoever.
See MVC::Neaf::X::Files for implementation.
File type detection is based on extentions so far, and the list is quite short. This MAY change in the future. Known file types are listed in %MVC::Neaf::X::Files::ExtType
hash. Patches welcome.
It is probably a bad idea to serve files in production using a web application framework. Use a real web server instead. Not need to set up one for merely testing icons/js/css, though.
alias()
$neaf->alias( $newpath => $oldpath )
Create a new name for already registered route. The handler will be executed as is, but the hooks and defaults will be re-calculated. So be careful.
[CAUTION] As of 0.21, alias
does NOT adhere tentative/override switches. This needs to be fixed in the future.
set_path_defaults
set_path_defaults( { version => 0.99 }, path => '/api', %options );
%options may include:
path - restrict this set of defaults to given prefix(es);
method - restrict this set of defaults to given method(s);
exclude - exclude some prefixes;
Append the given values to the hash returned by any route under the given path(s) and method(s).
Longer paths take over the shorter ones. Route's own default values take over any path-based defaults. Whatever the controller returns overrides all of these.
get_path_defaults
get_path_defaults ( $methods, $path, [ \%override ... ] )
Fetch default values for given (path, method) combo as a single hash.
add_hook()
$neaf->add_hook ( phase => CODEREF, %options );
Set hook that will be executed on a given request processing phase.
Valid phases include:
pre_route [die]
pre_logic [die]
pre_content
pre_render [die]
pre_reply [reverse]
pre_cleanup [reverse]
See "REQUEST PROCESSING PHASES AND HOOKS" in MVC::Neaf below for detailed discussion of each phase.
The CODEREF receives one and only argument - the $request
object. Return value is ignored, see explanation below.
Use $request
's session
, reply
, and stash
methods for communication between hooks.
Dying in a hook MAY cause interruption of request processing or merely a warning, depending on the phase.
%options may include:
path => '/path' - where the hook applies. Default is '/'. Multiple locations may be supplied via
[ /foo, /bar ...]
exclude => '/path/skip' - don't apply to these locations, even if under '/path'. Multiple locations may be supplied via
[ /foo, /bar ...]
method => 'METHOD' || [ list ] List of request HTTP methods to which given hook applies.
prepend => 0|1 - all other parameters being equal, hooks will be executed in order of adding. This option allows to override this and run given hook first. Note that this does NOT override path bubbling order.
get_hooks
get_hooks( $method, $path )
Fetch all hooks previously set for given path as a { phase => [ list ] } hash.
set_helper
set_helper( name => \&code, %options )
get_helpers
load_view()
load_view( "name", $view_object ); # stores object
# assuming it's an L<MVC::Neaf::View>
load_view( "name", $module_name, %params ); # calls new()
load_view( "name", $module_alias ); # ditto, see list of aliases below
load_view( "name", \&CODE ); # use that sub to generate
# content from hash
Setup view under name $name
. Subsequent requests with -view = $name
would be processed by that view object.
Use get_view
to fetch the object itself.
if object is given, just save it.
if module name + parameters is given, try to load module and create new() instance.
Short aliases
JS
,TT
, andDumper
may be used for correspondingMVC::Neaf::View::*
modules.if coderef is given, use it as a
render
method.
Returns the view object, NOT the object this method was called on.
set_forced_view()
$neaf->set_forced_view( $view )
If set, this view object will be user instead of ANY other view.
See "get_view".
Returns self.
magic( bool )
Get/set "magic" bit that triggers stuff like loading resources from __DATA__ on run() and such.
Neaf is magical by default.
load_resources()
$neaf->load_resources( $file_name || \*FH )
Load pseudo-files from a file (typically __DATA__
), say templates or static files.
As of 0.27, load_resources happens automatically upon run, but only once for each calling file. Use neaf->magic(0)
if you know better (e.g. you want to use __DATA__ for something else).
The format is as follows:
@@ /main.html view=TT
[% some_tt_template %]
@@ /favicon.ico format=base64 type=png
iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAABGdBTUEAAL
GPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hS<....more encoded lines>
This is obviously stolen from Mojolicious, in a slightly incompatible way.
An entry starts with a literal @@
, followed by 1 or more spaces, followed by a slash and a file name, optionally followed by a list of options, and finally by a newline.
Everything following the newline and until next such entry is considered file content.
Options may include:
type=ext | mime/type
format=base64
view=view_name,view_name...
- specify a template for given view(s) Leading slash will be stripped in this case.
Entries with unknown options will be skipped with a warning.
[EXPERIMENTAL] This method and exact format of data is being worked on.
set_session_handler()
$neaf->set_session_handler( %options )
Set a handler for managing sessions.
If such handler is set, the request object will provide session()
, save_session()
, and delete_session()
methods to manage cross-request user data.
% options may include:
engine
(required in method form, first argument in DSL form) - an object providing the storage primitives;ttl
- time to live for session (default is 0, which means until browser is closed);cookie
- name of cookie storing session id. The default is "session".view_as
- if set, add the whole session into data hash under this name before view processing.
The engine MUST provide the following methods (see MVC::Neaf::X::Session for details):
session_ttl (implemented in MVC::Neaf::X::Session);
session_id_regex (implemented in MVC::Neaf::X::Session);
get_session_id (implemented in MVC::Neaf::X::Session);
create_session (implemented in MVC::Neaf::X::Session);
save_session (required);
load_session (required);
delete_session (implemented in MVC::Neaf::X::Session);
set_error_handler()
$neaf->set_error_handler ( $status => CODEREF( $request, %options ), %where )
Set custom error handler.
Status MUST be a 3-digit number (as in HTTP).
%where may include path
, method
, and exclude
keys. If omitted, just install error handler globally.
Other allowed keys MAY appear in the future.
The following options will be passed to coderef:
status - status being returned;
caller - file:line where the route was set up; This is DEPRECATED and will silently disappear around version 0.25
error - exception, an MVC::Neaf::Exception object.
The coderef MUST return an unblessed hash just like a normal controller does.
In case of exception or unexpected return format default HTML error page will be returned.
Also available in static form, as set_error_handler( status => \%hash )
.
This is a synonym to sub { +{ status => $status, ... } }
.
on_error()
on_error( sub { my ($request, $error) = @_ } )
Install custom error handler for a dying controller. Neaf's own exceptions, redirects, and die \d\d\d
status returns will NOT trigger it.
E.g. write to log, or something.
Return value from this callback is ignored. If it dies, only a warning is emitted.
post_setup
This function is run after configuration has been completed, but before first request is served.
It goes as follows:
compile all the routes into a giant regexp;
Add HEAD handling to where only GET exists;
finish set_session_handler works
set the lock on route;
Despite the locking, further modifications are not prohibited. This MAY change in the future.
run()
$neaf->run();
Run the application. This SHOULD be the last statement in your application's main file.
When run() is called, the routes are compiled into one giant regex, and the post-setup is run, if needed.
Additionally if neaf is in magical mode, "load_resources" is called on the enclosing file's DATA descriptor. Magic mode is on by default. See "magic-bool".
If called in void context, assumes execution as CGI
and prints results to STDOUT
. If command line options are present at the moment, enters debug mode via MVC::Neaf::CLI. Call perl yourapp.pl --help
for more.
Otherwise returns a PSGI
-compliant coderef. This will also happen if you application is require
'd, meaning that it returns a true value and actually serves nothing until run()
is called again.
Running under mod_perl requires setting a handler with MVC::Neaf::Request::Apache2.
INTROSPECTION AND TESTING METHODS
run_test()
$neaf->run_test( \%PSGI_ENV, %options )
$neaf->run_test( "/path?parameter=value", %options )
Run a PSGI request and return a list of ($status, HTTP::Headers::Fast, $whole_content )
.
Returns just the content in scalar context.
Just as the name suggests, useful for testing only (it reduces boilerplate).
Continuation responses are supported, but will be returned in one chunk.
%options may include:
method - set method (default is GET)
cookie = \%hash - force HTTP_COOKIE header
header = \%hash - override some headers This gets overridden by type, cookie etc. in case of conflict
body = 'DATA' - force body in request
type - content-type of body
uploads - a hash of MVC::Neaf::Upload objects.
secure = 0|1 -
http
vshttps
override = \%hash - force certain data in
ENV
Gets overridden by all of the above.
get_routes()
$neaf->get_routes( $callback->(\%route_spec, $path, $method) )
Returns a 2-level hashref with ALL routes for inspection.
So $hash{'/path'}{'GET'} = { handler, expected params, description etc }
If callback is present, run it against route definition and append to hash its return value, but ONLY if it's true.
As of 0.20, route definitions are only protected by shallow copy, so be careful with them.
This SHOULD NOT be used by application itself.
RUN TIME METHODS
handle_request
handle_request( $req )
This is the CORE of Not Even A Framework. Should not be called directly - use run()
instead.
handle_request
really boils down to
my ($self, $req) = @_;
my $req->path =~ /($self->{GIANT_ROUTING_RE})/
or die 404;
my $endpoint = $self->{ROUTES}{$1}{ $req->method }
or die 405;
my $reply_hash = $endpoint->{CODE}->($req);
my $content = $reply_hash->{-view}->render( $reply_hash );
return [ $reply_hash->{-status}, [...], [ $content ] ];
The rest 200+ lines of it, spread across this module and MVC::Neaf::Route, are for running callbacks, handling corner cases, and substituting sane defaults.
get_view()
$route->get_view( "name", $lazy )
Fetch view object by name.
This is used to fetch/instantiate whatever is in -view
of the controller return hash.
Uses load_view
( name => name ) if needed, unless $lazy flag is on.
If "set_forced_view" was called, return its argument instead.
INTERNAL LOGIC METHODS
The following methods are part of NEAF's core and should not be called unless you want something very special.
The following terminology is used hereafter:
prefix - part of URI that matched given NEAF route;
suffix - anything after the matching part but before query parameters (the infamous
path_info
).
When recursive routing is applied, prefix
is left untouched, stem
becomes prefix, and suffix
is split into new stem
+ suffix
.
When a leaf route is found, it matches $suffix to its own regex and either dies 404 or proceeds with application logic.
find_route( $method, $suffix )
Find subtree that matches given ($method, $suffix) pair.
May die 404 or 405 if no suitable route is found.
Otherwise returns (route, new_stem, new_suffix).
dispatch_logic
dispatch_logic( $req, $prefix, $suffix )
Find a matching route and apply it to the request.
This is recursive, may die, and may spoil $req
.
Upon successful termination, a reply hash is returned. See also "dispatch_logic" in MVC::Neaf::Route.
dispatch_view
Apply view to a request.
neaf_base_dir()
Returns the containing directory of the first non-Neaf calling file, or cwd() with a warning otherwise.
DEPRECATED METHODS
Some methods become obsolete during Neaf development. Anything that is considered deprecated will continue to be supported for at least three minor versions after official deprecation and a corresponding warning being added.
Please keep an eye on Changes
though.
Here is the list of such methods, for the sake of completeness.
route
Old alias for "add_route".
LICENSE AND COPYRIGHT
This module is part of MVC::Neaf suite.
Copyright 2016-2023 Konstantin S. Uvarin khedin@cpan.org
.
This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.
See http://dev.perl.org/licenses/ for more information.