The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Plack::Middleware::PeriAHS::ParseRequest - Parse Riap request from HTTP request

VERSION

version 0.14

SYNOPSIS

 # in your app.psgi
 use Plack::Builder;

 builder {
     enable "PeriAHS::ParseRequest",
         match_uri => m!^/api(?<uri>/[^?]*)!;
 };

DESCRIPTION

This middleware's task is to parse Riap request from HTTP request (PSGI environment) and should normally be the first middleware put in the stack.

Parsing result

The result of parsing will be put in $env-{"riap.request"}> hashref.

Aside from that, this middleware also sets these for convenience of later middlewares:

  • $env->{'periahs.default_fmt'} => STR

    Default output format, will be used for response if fmt is not specified in Rinci request. Determined using some simple heuristics, i.e. graphical browser like Firefox or Chrome will get 'HTML', command-line browser like Wget or Curl will get 'Text', others will get 'json'.

  • $env->{'periahs.jsonp_callback'} => STR

    From form variable callback.

  • $env->{'periahs.riap_client'} => OBJ

    Store the Riap client (instance of Perinci::Access).

Parsing process

From HTTP header and request body. First parsing is done as per Riap::HTTP specification's requirement. All X-Riap-* request headers are parsed for Riap request key. When an unknown header is found, HTTP 400 error is returned. Then, request body is read for args. application/json document type is accepted, and also text/yaml (if accept_yaml configuration is enabled).

Additionally, the following are also done:

From URI. Request URI is checked against match_uri configuration. If URI doesn't match this regex, a 404 error response is returned. It is a convenient way to check for valid URLs as well as set Riap request keys, like:

 qr!^/api/(?<fmt>json|yaml)/!;

The default match_uri is qr/(?<uri>[^?]*)/.

From form variables. If parse_form is enabled, args request key will be set (or added) from GET/POST request variables, for example: http://host/api/foo/bar?a=1&b:j=[2] will set arguments a and b (":j" suffix means value is JSON-encoded; ":y" and ":p" are also accepted if the accept_yaml configurations are enabled). In addition, request variables -riap-* are also accepted for setting other Riap request keys. Unknown Riap request key or encoding suffix will result in 400 error.

If request format is JSON and form variable callback is defined, then it is assumed to specify callback for JSONP instead part of args. "callback(json)" will be returned instead of just "json".

From URI (2, path info). If parse_path_info configuration is enabled, and uri Riap request key has been set (so metadata can be retrieved), args will be set (or added) from URI path info. See "parse_path_info" in the configuration documentation.

 http://host/api/v1/Module::Sub/func/a1/a2/a3

will result in ['a1', 'a2', 'a3'] being fed into Perinci::Sub::GetArgs::Array. An unsuccessful parsing will result in HTTP 400 error.

CONFIGURATIONS

  • match_uri => REGEX or [REGEX, CODE] (default qr/.?/)

    This provides an easy way to extract Riap request keys (typically uri) from HTTP request's URI. Put named captures inside the regex and it will set the corresponding Riap request keys, e.g.:

     qr!^/api(?<uri>/[^?]*)!

    If you need to do some processing, you can also specify a 2-element array containing regex and code. When supplied this, the middleware will NOT automatically set Riap request keys with the named captures; instead, your code should do it. Code will be supplied ($env, \%match) and should set $env->{'riap.request'} as needed. An example:

     match_uri => [
         qr!^/api
            (?: /(?<module>[\w.]+)?
              (?: /(?<func>[\w+]+) )?
            )?!x,
         sub {
             my ($env, $match) = @_;
             if (defined $match->{module}) {
                 $match->{module} =~ s!\.!/!g;
                 $env->{'riap.request'}{uri} = "/$match->{module}/" .
                     ($match->{func} // "");
             }
         }];

    Given URI /api/Foo.Bar/baz, uri Riap request key will be set to /Foo/Bar/baz.

  • accept_yaml => BOOL (default 0)

    Whether to accept YAML-encoded data in HTTP request body and form for args Riap request key. If you only want to deal with JSON, keep this off.

  • parse_form => BOOL (default 1)

    Whether to parse args keys and Riap request keys from form (GET/POST) variable of the name -x-riap-* (notice the prefix dash). If an argument is already defined (e.g. from request body) or request key is already defined (e.g. from X-Riap-* HTTP request header), it will be skipped.

  • parse_path_info => BOOL (default 0)

    Whether to parse arguments from $env->{PATH_INFO}. Note that this will require a Riap meta request to the backend, to get the specification for function arguments. You'll also most of the time need to prepare the PATH_INFO first. Example:

     parse_path_info => 1,
     match_uri => [
         qr!^/ga/(?<mod>[^?/]+)(?:
                /?(?:
                    (?<func>[^?/]+)?:
                    (<pi>/?[^?]*)
                )
            )!x,
         sub {
             my ($env, $m) = @_;
             $m->{mod} =~ s!::!/!g;
             $m->{func} //= "";
             $env->{'riap.request'}{uri} = "/$m->{mod}/$m->{func}";
             $env->{PATH_INFO} = $m->{pi};
         },
     ]
  • riap_client => OBJ

    By default, a Perinci::Access object will be instantiated (and later put into $env-{'periahs.riap_client'}> for the next middlewares) to perform Riap requests. You can supply a custom object here.

SEE ALSO

Perinci::Access::HTTP::Server

AUTHOR

Steven Haryanto <stevenharyanto@gmail.com>

COPYRIGHT AND LICENSE

This software is copyright (c) 2012 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.