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

This document describes version 0.60 of Plack::Middleware::PeriAHS::ParseRequest (from Perl distribution Perinci-Access-HTTP-Server), released on 2016-03-16.

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 (by default instance of Perinci::Access::Schemeless).

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 (This step will be skipped if match_uri configuration is not set or empty). 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 configuration 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" is 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 form variables (2, ReForm). PeriAHS has support for ReForm. If parse_reform configuration is set to true and form variable -submit is also set to true, then the resulting args from previous step will be further fed to ReForm object. See the "parse_reform" in the configuration documentation.

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

  • riap_uri_prefix => STR (default: '')

    If set, Riap request uri will be prefixed by this. For example, you are exposing Perl modules at YourApp::API::* (e.g. YourApp::API::Module1. You want to access this module via Riap request uri /Module1/func instead of /YourApp/API/Module1/func. In that case, you can set riap_uri_prefix to /YourApp/API/ (notice the ending slash).

  • server_host => STR

    Set server host. Used by get_http_request_url. The default will be retrieved from PSGI environment HTTP_HOST.

  • server_port => STR

    Set server port. Used by get_http_request_url. The default will be retrieved from PSGI environment HTTP_HOST.

  • server_path => STR (default: '/api')

    Set server URI path. Used by get_http_request_url.

  • get_http_request_url => CODE (default: code)

    Should be set to code that returns HTTP request URL. Code will be passed ($self, $env, $rreq), where $rreq is the Riap request hash. The default code will return something like:

     http(s)://<SERVER_HOST>:<SERVER_PORT><SERVER_PATH><RIAP_REQUEST_URI>

    for example:

     https://cpanlists.org/api/get_list

    This code is currently used by the PeriAHS::Respond middleware to print text hints.

    Usually you do not need to customize this, you can already do some customization by setting server_path or riap_uri_prefix, unless you have a more custom URL scheme.

  • 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.

  • match_uri_errmsg => STR

    Show custom error message when URI does not match match_uri.

  • 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_reform => BOOL (default 0)

    Whether to parse arguments in args request key using ReForm. Even if enabled, will only be done if -submit form variable is set to true.

    This configuration is used only if you render forms using ReForm and want to process the submitted form.

    Form specification will be created (converted) from args property in function metadata, which means that a meta Riap request to the backend will be performed first to get this metadata.

  • 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::Schemeless 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, for example the more general Perinci::Access object to allow requesting from remote URLs.

  • use_tx => BOOL (default 0)

    Will be passed to Perinci::Access::Schemeless constructor.

  • custom_tx_manager => STR|CODE

    Will be passed to Perinci::Access::Schemeless constructor.

  • php_clients_ua_re => REGEX (default: qr(Phinci|/php|php/)i)

    What regex should be used to identify PHP Riap clients. Riap clients often (should) send ua key identifying itself, e.g. Phinci/20130308.1, Perinci/0.12, etc.

  • deconfuse_php_clients => BOOL (default: 1)

    Whether to do special handling for PHP Riap clients (identified by php_clients_ua_re). PHP clients often confuse empty array [] with empty hash {}, since both are Array() in PHP. If this setting is turned on, the server makes sure args becomes {} when client sends [], and {} arguments become [] or vice versa according to hint provided by function metadata.

HOMEPAGE

Please visit the project's homepage at https://metacpan.org/release/Perinci-Access-HTTP-Server.

SOURCE

Source repository is at https://github.com/sharyanto/perl-Perinci-Access-HTTP-Server.

BUGS

Please report any bugs or feature requests on the bugtracker website https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Access-HTTP-Server

When submitting a bug or request, please include a test-file or a patch to an existing test-file that illustrates the bug or desired feature.

SEE ALSO

Perinci::Access::HTTP::Server

AUTHOR

perlancar <perlancar@cpan.org>

COPYRIGHT AND LICENSE

This software is copyright (c) 2016 by perlancar@cpan.org.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.