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

NAME

Web::DataService::Request - object class for data service requests

SYNOPSIS

As each incoming request is handled by the Web::DataService framework, a request object is created to represent it. This object is blessed into a subclass of Web::DataService::Request which provides the methods listed here and also includes one or more roles with methods that you have written for evaluating the request and doing the appropriate fetching/storing on the backend data system.

The simplest way for the main application to handle a request is as follows:

    Web::DataService->handle_request(request);

This call uses the request function provided by the foundation framework (Dancer) to get the "outer" object representing this request from the point of view of the foundation framework, and then passes it to the handle_request method of Web::DataService. In the process of handling the request, a new "inner" request object is generated and blessed into an appropriate subclass of Web::DataService::Request.

If you wish more control over this process, you can substitute the following:

    my $inner = Web::DataService->new_request(request);
    
    # You can put code here to check the attributes of $inner and possibly
    # alter them...
    
    $inner->execute;

Whichever of these code fragments you use should go into a Dancer route handler.

Request handling process

The request handling process carried out by handle_request works as follows:

  1. The request URL path and parameters are parsed according to the active set of data service features and special parameters. Depending upon the set of data service features that are active, the path may be processed before moving on to the next step. The following is not an exhaustive list, but illustrates the kinds of processing that are done:

    • If more than one data service is defined, the appropriate one is selected to handle this request.

    • If the data service has the attribute "path_prefix", this prefix is removed from the path.

    • If the feature 'format_suffix' is active and the path ends in a format suffix such as .json, then that suffix is removed and later used to set the "format" attribute of the request.

    • If the feature 'doc_paths' is active and the path ends in '_doc' or in '/index' then this suffix is removed and the "is_doc_request" attribute of the request is set.

    • If the special parameter 'document' is active and this parameter was included with the request, then the "is_doc_request" attribute of the request is set.

  2. The modified request path is matched against the set of data service node paths. Nodes with either of the attributes file_dir or collapse_tree match as prefixes, all others must match exactly. If none of the nodes match, then the request is rejected with a HTTP 404 error. Otherwise, a new request object is created and configured using the attributes of the matching node.

If you used new_request instead of handle_request, then you get control at this point and can modify the request before calling $request->execute to finish the process.

3.

If the matching node has the file_path attribute, then the contents of the specified file are returned using the foundation framework (i.e. Dancer). If the node has the file_dir attribute instead, then the remainder of the request path is applied as a relative path to that directory. The result of the request will be either the contents of a matching file or a HTTP 404 error.

4.

Otherwise, the new request will be blessed into an automatically generated subclass of Web::DataService::Request. These subclasses are generated according to the value of the "role" attribute of the matching node. Each different role generates two subclasses, one for documentation requests and one for operation requests. These classes are composed so that they contain the necessary methods for documentation rendering and operation execution, respectively, along with all of the definitions from the primary role (this role module must be written by the application author).

5.

If the "is_doc_request" attribute has been set, or if the matching node does not have a value for the "method" attribute, then the documentation directory is checked for a template corresponding to the matching node. If not found, the appropriate default template is used. This template is rendered to produce a documentation page, which is returned as the result of the request.

6.

Otherwise, we can assume that the node has a "method" attribute. The request parameters are then checked against the ruleset named by the "ruleset" attribute, or the ruleset corresponding to the node path if this attribute is not set.

7.

The output is then configured according to the output blocks(s) indicated by the "output" attribute plus those indicated by "optional_output" in conjunction with the special parameter "show".

8.

The method specified by the node attribute "method" is then called. This method (which must be written by the application author) is responsible for fetching and/or storing data using the backend system and specifying what the result of the operation should be.

9.

If the result of the operation is one or more data records, these records are processed according to the specification contained in the selected output block(s), and are then serialized by the module corresponding to the selected output format. If "count" or "datainfo" were requested, or if any warnings or errors were generated during the execution of the request, this material is included in an appropriate way by the serialization module. The resulting response body is returned using the foundation framework.

10.

If the result of the operation is instead a piece of non-record data (i.e. an image or other binary data), it is returned as the response body using the foundation framework.

METHODS

Constructor

new ( attributes... )

You will not need to call this method directly; instead, you should call the handle_request method of Web::DataService, which calls it internally after carrying out other processing.

Execution

execute ( )

Executes this request, and returns the serialized response data. If your main application uses handle_request, then you will not need to call this method because handle_request calls it internally.

error_result ( error )

Aborts processing of the request and causes a HTTP error response to be returned to the client. You will probably not need to call this method, since the preferred way of generating an error condition is to call die. The parameter can be any of the following:

  • A HTTP error code, such as "404" or "500".

  • An error message, which will be written to the log. For security reasons, the client will just get back a HTTP 500 response that tells them a server error occurred and they should contact the server administrator.

  • A validation result object from HTTP::Validate. The client will get back a HTTP 400 response containing the error and warning messages contained within it.

Attribute accessors

ds

Returns a reference to the data service instance with which this request is associated.

outer

Returns a reference to the "outer" request object defined by the foundation framework.

path

Returns the raw path associated with the request.

node_path

Returns the path of the node that matches this request.

rest_path

If the node path matches the processed request path as a prefix, this accessor returns the remainder of the path. Otherwise, it returns undef.

is_invalid_request

Returns true if this request could not be matched to a node, or is otherwise invalid. Returns false otherwise.

is_doc_request

Returns true if this request has been determined to be a request for documentation, according to the features and special parameters enabled for this data service. Returns false otherwise.

is_node_path

Returns true if the request path exactly matches the path of a data service node, false otherwise.

http_method

Returns (or sets) the HTTP method associated with the request.

request_url

Returns the complete request URL.

base_url

Returns the base component of the request URL, of the form "http://some.host/" or something similar.

root_url

Returns the base URL plus the path prefix (if any) for this data service.

path_prefix

Returns the path prefix (if any) for this data service.

data_info

Returns a hash containing information about the request and the data to be returned. The hash keys will include some or all of the following, depending upon the configuration of the data service.

title, data_provider, data_source, data_license, license_url

The values of these keys will be the corresponding attributes of the data service. They may be undefined if no value was specified for them either when the data service was instantiated or in the configuration file maintained by the foundation framework.

access_time

The current time.

data_url

The complete request URL.

documentation_url

A URL that will return a documentation page describing the selected data service node.

data_info_keys

Returns a list of the keys documented for data_info, in a canonical order for use by the serialization modules.

contact_info

Returns a hash whose keys are name and email. The values will be the values of the data service attributes contact_name and contact_email, respectively.

generate_url ( attrs )

This method returns a URL generated from the specified attributes, which must be given either as a hashref or as a string:

    # either of the following:
    
    $url = $request->generate_url( { op => 'abc/def', format => 'json', params => 'foo=1' } );
    $url = $request->generate_url( "op:abc/def.json?foo=1" );

The attributes are as follows:

node

Generate a URL which will request documentation using the node path given by the value of this attribute. In the string form, this is represented by a prefix of "node:".

op

Generate a URL which will request a data service operation using the node path given by the value of this attribute. In the string form, this is represented by a prefix of "op:".

path

Generate a URL which will request the exact path given. This is used to generate URLs for requesting files, such as CSS files. In the string form, this is represented by a prefix of "path:".

format

The generated URL will request output in the specified format. Depending upon the features enabled for this data service, that may mean either adding the specified value as a suffix to the URL path, or adding a special parameter. In the string form, this is represented by adding '.' followed by the format to the path (this syntax is fixed no matter which data service features are enabled).

params

Configure the URL to include the specified parameters. The value of this attribute must be either an arrayref with an even number of elements or a single URL parameter string such as "foo=1&bar=2". In the string form, this is represented by a '?' followed by the parameter string.

type

The value of this attribute must be either abs, rel, or site. If "abs" is given, then the generated URL will begin with "http[s]://hostname[:port]/. If "site", then the generated URL will begin with "/" followed by the path prefix for this data service (if any). If "relative", no prefix will be added to the generated URL. In this case, you must make sure to specify a path that will work properly relative to the URL of the page on which you intend to display it.

If this attribute is not specified, it defaults to "site". In the string form, this is represented by modifying the prefix, i.e. "oprel:" or "opabs:" instead of just "op:".

node_attr ( name )

Returns the value of the specified attribute of the node matching this request, or undef if the attribute is not defined for that node.

special_value ( param )

Returns the value of the specified special parameter, if it is enabled for this data service and if it was included with this request. Returns undef otherwise.

special_given ( param )

Returns true if the specified special parameter was included in this request and is enabled for this data service, regardless of its value. Returns false otherwise.

default_limit

Returns the default result limit, if any. This is used in generating documentation.

Documentation methods

The following methods are only available with documentation requests. They can be called from documentation templates as follows:

    <% result = request.method_name(args) %>

or, to include the result directly in the rendered output:

    <% request.method_name(args) %>

In either case, "request" is a variable automatically provided to the templating engine. The string "result" should be replaced by whatever variable you wish to assign the result to, and "method_name" and "args" by the desired method and arguments.

These methods are all packaged up in blocks defined by doc_defs.tt, so you will not need to call them directly unless you want to make substantive changes to the look of the documentation pages.

document_node

Returns the documentation string for the node matching this request, or the empty string if none was defined.

list_navtrail

Returns a list of navigation trail components for the current request, in Pod format. These are generated componentwise from the node path.

document_usage

Returns a string in Pod format listing the URLs generated from the node attribute "usage", if any were given for this node.

list_subnodes

Returns a list of the node paths corresponding to all subnodes of the current one for which the place attribute was set.

document_subnodes

Returns a string in Pod format documenting the subnodes of the current one for which the place attribute was set.

document_params

Returns a string in Pod format documenting the parameters available for this request. This is automatically generated from the corresponding ruleset, if one was defined.

list_http_methods

Returns a list of HTTP methods that are allowed for this request path.

document_http_methods

Returns a string in Pod format documenting the HTTP methods that are allowed for this request path.

document_response

Returns a string in Pod format documenting the all of the fields that might be included in the result.

output_label

Returns the value of the node attribute "output_label", or the default value "basic" if none was defined.

optional_output

Returns the value of the node attribute "optional_output", if this attribute was defined.

document_formats ( options )

Returns a string in Pod format documenting the formats allowed for this node. If a parameter is specified, it must be a hashref. If this includes the key 'all' with a true value, then all formats defined for this data service are included. If it includes the key 'extended' with a true value, then a description of each format is included.

default_format

Return the name of the default format (if any was specified) for this node.

document_vocabs ( options )

Return a string in Pod format documenting the vocabularies allowed for this node. If a parameter is specified, it must be a hashref. If this includes the key 'all' with a true value, then all vocabularies defined for this data service are included. If it includes the key 'extended' with a true value, then a description of each vocabulary is included.

output_format

You can use this method to check whether the response is to be rendered into HTML or returned as Pod text. The values returned are html and <pod> respectively.

Operation methods

The following methods are only available with operation requests. They can be called from any of the operation methods included in the application role module(s).

get_connection

This method can only be used if you explicitly specified a backend plugin when instantiating the data service, or if the module Dancer::Plugin::Database was required in your main application before Web::DataService.

Assuming that the proper connection information is present in the application configuration file, this method will return a connection to your backend data store.

exception ( code, message )

Returns an exception object encoding the specified HTTP result code and a message to go with it. This exception object can be used as an argument to 'die'. Its type is Web::DataService::Exception.

debug

Returns true if the data service process is running under debug mode. This can be used to output extra debugging information as appropriate.

debug_line ( text )

Print the specified text to standard error, followed by a newline, if debug mode is enabled for this data service process. This can be used, for example, to output the text of SQL statements executed on the underlying database, and similar information, for debugging purposes. For example:

    $request->debug_line($sql) if $request->debug;

param_keys ( )

Returns a list of the parameter keys corresponding to the request parameters. These will generally be the same as the parameter names, but may be different if you include the keys key and/or alias in the parameter validation rulesets (see ruleset configuration).

clean_param ( param )

Returns the cleaned value of the specified parameter, or undefined if the parameter was not included in the request. If more than one parameter value was given, the result will be an array ref.

clean_param_list ( param )

Returns a list of all the cleaned values of the specified parameter (one or more), or empty if the parameter was not included in the request.

clean_param_hash ( param )

Returns a hashref whose keys are all of the cleaned values of the specified parameter, or an empty hashref if the parameter was not included in the request.

param_given ( param )

Returns true if the specified parameter was included in there request, whether or not it had a valid value. Returns false otherwise.

params_for_display

Returns a list of (parameter, value) pairs for use in responding to the 'datainfo' special parameter. This result list leaves out any special parameters that do not affect the content of the result. Multiple values are concatenated together using commas.

validate_params ( ruleset_name, param... )

Validates the specified parameters (which may be hash or list refs of parameters and values) to the specified ruleset. Returns the result, which will be an object of type HTTP::Validate::Result that can then be queried for success or failure, error messages, etc. The primary purpose for this method is to allow validation of data records before they are added to the underlying database.

raw_body

Returns the request body as an un-decoded string. If the request does not contain a body, returns the empty string. The primary purpose for this method is to accept data for addition to the underlying database.

decode_body

Attempts to decode the request body, if it is in a known format. Currently, the only two formats understood are JSON and text. A JSON body will be decoded into a Perl data structure, while a text body will be split into a list of lines. If no body exists, the undefined value is returned. If an error occurs during JSON decoding, it will be returned as a second item. Consequently, the return value of this method should be assigned to a two-element list.

has_block ( block )

Returns true if the specified output block was selected for this request. The parameter can be either the name of the block or the parameter value by which it would be selected.

select_list ( subst )

Returns a list of strings derived from the 'select' configuration records found in the output blocks selected for this request. You can use these records to specify which fields need to be retrieved from the backend data store. Any given string will only appear once in the list, even if it occurs in multiple 'select' records.

The optional argument should be a hashref, indicating substitutions to be made. For example, given the following code,

    $ds->define_block( 'block1' => 
        { select => '$a.name', '$a.value', 'c.size' },
        ... );
    
    # ...and in a different subroutine...
    
    my @fields = $request->select_list( { a => 'table1', b => 'table2' } )

The result will include table1.name, table1.value, and c.size.

If you are using an SQL-based backend, and if you set up the 'select' records properly, you can use this method (or see select_string below) to build a SELECT statement that will fetch exactly the information needed for the selected set of output blocks. This is important if your application allows optional output blocks that can be selected arbitrarily by the client. If you are using a non-SQL backend, you are free to use this in any way that makes sense given the backend interface.

select_hash ( subst )

Returns the same set of strings as select_list, but as the keys in a hash. The values will all be 1.

select_string ( subst )

Returns the same set of strings as select_list, but joined into a single string with each item separated by a comma and a space.

substitute_select ( variable => value, variable => value ... )

Make substitutions in the select list. For example, if passed the arguments 'v => xt', then anywhere the string '$v' appears in the select list, that string will be replaced by 'xt'. This method should be called before 'select_list' or 'select_string'. The intended use is to select between one or more alternate database tables.

tables_hash

Returns a hashref whose keys are derived from the 'select' configuration records found in the output blocks selected for this request. The keys from this hash will be the values specified by any 'tables' attributes in those configuration records. The values will all be 1.

If you are using an SQL-based backend, and if you set up the 'select' records properly, you can use this method to keep track of which database tables will be needed in order to build a query that can satisfy all of the data blocks included in this request. You can use the set of keys to constuct an appropriate list of table joins. If you are using a non-SQL backend, you can use this in any way that makes sense given the backend interface.

If you call this method multiple times, you will get a reference to the same hash each time. This means that you can safely add and remove keys during your own processing.

add_table ( alias, [full_name] )

Add an extra key to the tables hash. The optional second parameter can be the full name of the table to be included, but this is ignored. Note that adding a table to the table hash will not automatically include that table in any SQL statements. You need to check the table hash and add it yourself if the appropriate key is found.

filter_hash

Returns a hashref whose keys are derived from the 'filter' configuration records found in the output blocks selected for this request. The values will all be 1.

If you are using an SQL-based backend, and if you set up the 'filter' records properly, you can use this method to get a list of (unique) filter expressions to use in building a query that can satisfy all of the data blocks included in this request. (Note: you will almost always need to add other filter expressions derived from parameter values as well). If you are using a non-SQL backend, you can use this in any way that makes sense given the backend interface.

If you call this method multiple times, you will get a reference to the same hash each time. This means that you can safely add and remove keys during your own processing.

output_field_list

This method returns the output field list for the current request. This is the actual list, not a copy, so it can be manipulated. This is a real hack, which will probably be removed from a future version of this module. But for the time being, you can use it (for example) to go through the list and prune fields that will not be used.

delete_output_field ( field )

Remove the specified output field from the list. The first field whose name (not label) matches the argument is removed, regardless of what output block it occurs in. If no fields match, nothing will be removed.

result_limit

Returns the result limit specified for this request, or undefined if none was given or if all was specified. Even though Web::DataService will always truncate the result set if a limit was given, you may want to include this limit value in any queries you make to the backend so as to prevent your server from doing unnecessary work.

result_offset ( will_handle )

Returns true if a result offset was specified for this request, or zero if none was specified. If the argument value is true, then Web::DataService assumes that you will handle the process of offsetting the data result, e.g. by using modifying your backend query appropriately (see sql_limit_clause below).

If the argument is false, or if you never call either this method or sql_limit_clause, then (if an offset was specified for this request) Web::DataService will automatically discard the corresponding number of records from the beginning of the result set before serializing the results.

sql_limit_clause ( will_handle )

Returns a string whose value is an LIMIT clause that can be added to an SQL query to generate a result set in accordance with result limit and offset (if any) specified for this request. If the argument is true, then Web::DataService assumes that you will actually do this.

If the argument is false, or if you never call either this method or result_offset, then (if an offset was specified for this request) Web::DataService will automatically discard the corresponding number of records from the beginning of the result set before serializing the results.

If a result limit was specified for this request, and if the result set you generate exceeds this size, Web::DataService will always truncate it to match the specified limit.

sql_count_clause ( )

Returns a string that can be added to an SQL statement to generate a result count in accordance with the request parameters. If the special parameter "count" was specified for this request, the result will be SQL_CALC_FOUND_ROWS. Otherwise, it will be the empty string.

If you are using a non-SQL backend, you can still use this as a boolean variable to determine if the result should include a count of the number of records found.

sql_count_rows ( )

Execute the SQL statement "SELECT FOUND ROWS" and store the result for use in generating the response header. But only do this if the request parameters specify that result counts should be returned.

set_result_count ( count )

Use this method to tell Web::DataService the result count if you are using sth_result. In this case, you will generally need to execute a separate query such as "SELECT FOUND_ROWS()" after your main query.

output_format

Returns the name of the response format selected for this request.

output_vocab

Returns the name of the response vocabulary selected for this request. If no vocabularies have been defined for this data service, it will return "null", the name of the default vocabulary.

output_linebreak

Returns the string to be inserted between output lines in text-based response formats. This will be either a carriage return, a linefeed, or both.

result_limit

Returns the limit (if any) specified for the size of the result set.

result_offset

Returns the offset (if any) specified for the start of the result set.

display_header

Returns true if header material is to be displayed in text-based response formats, false otherwise.

display_datainfo

Returns true if a description of the dataset is to be included in the response, false otherwise.

display_counts

Returns true if result counts and elapsed time are to be included in the response, false otherwise.

save_output

Returns true if the special parameter 'save' was included in the request.

get_config

Returns a hashref providing access to the attributes defined in the application configuration file. Allows you to include application-specific directives in the file and retrieve them as needed from your operation methods.

set_content_type

Specify the value for the "Content-type" HTTP response header. You will probably not need to call this, since it is set automatically based on the selected response format.

Returns an exception object which can be used as an argument to die. This will abort processing of the current request and generate an HTTP error result. The first argument must be a valid HTTP error code.

Result methods

These methods are also available with operation requests. You will need to call at least one of them from each of your operation methods. These methods are how you tell Web::DataService the result of each operation.

You can make more than one of these calls from a single operation, but note that each call (except for add_result in some cases) wipes out any result specified by previous calls.

single_result ( record )

The argument must be a hashref representing a single data record. The result of this operation will be that single record.

list_result ( record... )

You can call this method either with a single arrayref argument whose members are hashrefs, or with a list of hashrefs. Either way, the result of this operation will be the specified list of records.

add_result ( record... )

Adds the specified record(s) to a result set previously specified by list_result. All arguments must be hashrefs.

sth_result ( sth )

The argument must be a valid DBI statement handle that has already been executed. Once your operation method returns, Web::DataService will then fetch the result records from this sth one by one, process them according to the selected set of output blocks for this request, and serialize the result.

If you use this result method, you will need to call either display_counts or sql_count_clause to determine if a result count is needed. If so, execute a "SELECT FOUND_ROWS()" query (or the equivalent) and use set_result_count to tell Web::DataService how many records were found.

data_result ( data )

The argument must be either a scalar or a reference to a scalar. In either case, this data will be returned as the result of the operation without any further processing. You can use this, for example, to return images or other binary data. You can use set_content_type to set the result content type, or you can rely on the suffix of the URL path if appropriate.

clear_result

This call clears any results that have been specified for this operation by any of the other methods in this section.

skip_output_record ( record )

The given record is marked in such a way as to cause it to be omitted from the output. The record counts are not updated, however, which limits its utility. This method can be called from an operation method if list_result is being used, or else from a before_record_hook routine.

select_output_block ( record, block_name )

The given record will be output using the specified output block, instead of the output block specified by the operation node attributes. That output block will be configured if it has not yet been configured for this operation. Optional output blocks are not affected. A future version of this module will provide ways to alter the optional output blocks.

add_warning ( message )

Add the specified warning message to this request. The warnings will be automatically included in the result, in a manner appropriate for the selected response format.

warnings ( )

Return a list of the warning messages (if any) that have been added to this request.

add_caution ( message )

Add the specified caution message to this request. The caution messages will be automatically included in the result, in a manner appropriate for the selected response format.

cautions ( )

Return a list of the caution messages (if any) that have been added to this request.

add_error ( message )

Add the specified error message to this request. The error messages will be automatically included in the result, in a manner appropriate for the selected response format.

errors ( )

Return a list of the error messages (if any) that have been added to this request.

AUTHOR

mmcclenn "at" cpan.org

BUGS

Please report any bugs or feature requests to bug-web-dataservice at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Web-DataService. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

COPYRIGHT & LICENSE

Copyright 2014 Michael McClennen, all rights reserved.

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

8 POD Errors

The following errors were encountered while parsing the POD:

Around line 733:

Expected text after =item, not a number

Around line 744:

Expected text after =item, not a number

Around line 752:

Expected text after =item, not a number

Around line 759:

Expected text after =item, not a number

Around line 765:

Expected text after =item, not a number

Around line 772:

Expected text after =item, not a number

Around line 782:

Expected text after =item, not a number

Around line 1441:

Unknown directive: =h3ad3