NAME
Plack::Middleware::SubSpec::ParseRequest - Parse sub call request from HTTP request
VERSION
version 0.06
SYNOPSIS
# in your app.psgi
use Plack::Builder;
builder {
enable "SubSpec::ParseRequest"
uri_pattern => m!^/api/v1/(?<module>[^?]+)?/?(?<sub>[^?/]+)?!,
after_parse => sub {
my $env = shift;
for ($env->{"ss.request.module"}) {
last unless $_;
s!/!::!g;
$_ = "My::API::$_" unless /^My::API::/;
}
};
# enable other middlewares ...
};
DESCRIPTION
This middleware parses sub call request information from HTTP request (PSGI environment) and should normally be the first middleware put in the stack. It parses module name and subroutine name from the URI, call arguments from URI/request body, and call options from URI/HTTP headers.
Parsing result
The result of parsing will be put in these PSGI environment keys:
ss.request.module
The module name which contains the subroutine to call, a string scalar.
ss.request.sub
The subroutine name to call, a string scalar.
ss.request.args
The call arguments, hashref.
ss.request.opts
Call options. A hashref with the following known keys:
type => STR 'call'/'usage'/'spec' (default 'call')
Specify request type. 'call' is the default, meaning a request to call the subroutine and return the result. 'usage' requests help/usage information instead. 'spec' requests sub spec instead.
log_level => INT 0 to 6 or STR (default 0)
Specify log level. If set to values larger than 0, when calling the subroutine, log messages produced by Log::Any will be passed to the HTTP client. The number specifies log level: 0 is none, 1 fatal, 2 error, 3 warn, 4 info, 5 debug, 6 trace]. Alternatively, the string "fatal", "error", etc can be used instead.
mark_log => BOOL (default 0)
Prepend each log message with "L" (and response with "R"). Only useful/relevant when turning on log_level, so clients can parse/separate log message from response.
See Plack::Middleware::SubSpec::ServeCall, the middleware which implements this.
output_format => STR 'yaml'/'json'/'php'/'pretty'/'nopretty'/'html' (default 'json' or 'pretty' or 'html')
Specify preferred output format. The default is 'json', or 'html' if User-Agent is detected as a GUI browser. Format detection and formatting is done by Plack::Middleware::SubSpec::ServeCall.
Parsing process
First, uri_pattern configuration is checked. It should contain a regex with named captures and will be matched against request URI. For example:
qr!^/api/v1/(?<module>[^?/]+)/(?<sub>[^?/]+)!
If URI doesn't match this regex, a 400 error response is returned.
The $+{module}
capture, after some processing (replacement of all nonalphanum characters into "::") will be put into $env-
{"ss.request.module"}>.
The $+{sub}
capture will be put into $env-
{"ss.request.sub"}>.
After that, call arguments will be parsed from the rest of the URI, or from query (GET) parameters, or from request body (POST).
From the rest of the URI. For example, if URI is /api/v1/Module1.SubMod1/func1/a1/a2?a3=val&a4=val
then after uri_pattern is matched it will become "/a1/a2?a3=val&a4=val"
and $env-
{"ss.request.module"}> is Module1::SubMod1
and $env-
{"ss.request.sub"}> is func1
. /a1/a2 will be split into array ["a1", "a2"] and processed with Sub::Spec::GetArgs::Array. After that, query parameters will be processed as follows:
Parameter name maps to sub argument name, but it can be suffixed with ":<CHAR>" to mean that the parameter value is encoded. This allows client to send complex data structure arguments. :j
means JSON-encoded, :y
means YAML-encoded, and :p
means PHP-serialization-encoded. You can disable this argument decoding by setting per_arg_encoding configuration to false.
Finally, request options are parsed from HTTP request headers matching X-SS-<option-name>. For example, X-SS-Log-Level
can be used to set log_level
option. Unknown headers will simply be ignored.
CONFIGURATIONS
uri_pattern => REGEX
Regexp to match against URI, to extract module and sub name. Should contain named captures for
module
,sub
. If regexp doesn't match, a 400 error response will be generated.allowable_commands => ARRAY (default [qw/call help spec listmod listsub/])
Which commands to allow. Default is all commands. If you want to disable certain commands, exclude it from the list. In principle the most important command is 'call', while the others are just helpers.
parse_args_from_web_form => BOOL (default 1)
Whether to parse arguments from web form (GET/POST parameters)
parse_args_from_body => BOOL (default 1)
Whether to parse arguments from body (if document type is
text/yaml
,application/json
, orapplication/vnd.php.serialized
.parse_args_from_path_info => BOOL (default 0)
Whether to parse arguments from path info. Note that uri_pattern will first be removed from URI before args are extracted. Also, parsing arguments from path info (array form,
/arg0/arg1/...
) requires that we have the sub spec first. So we need to execute the Plack::Middleware::SubSpec::LoadSpec first. The actual parsing is done by Plack::Middleware::SubSpec::ParseArgsFromPathInfo first.allow_logs => BOOL (default 1)
Whether to allow request for returning log messages (request option 'log_level' with value larger than 0). You might want to turn this off on production servers.
accept_json => BOOL (default 1)
Whether to accept JSON-encoded data (either in GET/POST request variables, etc).
accept_php => BOOL (default 1)
Whether to accept PHP serialization-encoded data (either in GET/POST request variables, etc). If you only want to deal with, say, JSON encoding, you might want to turn this off.
accept_yaml => BOOL (default 1)
Whether to accept YAML-encoded data (either in GET/POST request variables, etc). If you only want to deal with, say, JSON encoding, you might want to turn this off.
per_arg_encoding => BOOL (default 1)
Whether we should allow each GET/POST request variable to be encoded, e.g. http://foo?arg1:j=%5B1,2,3%5D ({arg1=>[1, 2, 3]}).
after_parse => CODE
If set, the specified code will be called with arguments ($self, $env) to allow doing more parsing/checks.
SEE ALSO
AUTHOR
Steven Haryanto <stevenharyanto@gmail.com>
COPYRIGHT AND LICENSE
This software is copyright (c) 2011 by Steven Haryanto.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.