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

Name

REST::Consumer - General client for interacting with json data in HTTP Restful services

Synopsis

This module provides an interface that encapsulates building an http request, sending the request, and parsing a json response. It also retries on failed requests and has configurable timeouts.

Usage

To make a request, create an instance of the client and then call the get(), post(), put(), or delete() methods. (Alternatively, call ->get_processed_response() and supply your own method name.)

        # Required parameters:
        my $client = REST::Consumer->new(
                host => 'service.somewhere.com',
                port => 80,
        );


        # Optional parameters:
        my $client = REST::Consumer->new(
                host        => 'service.somewhere.com',
                port        => 80,
                timeout     => 60, (default 10)
                retry       => 10, (default 3)
                retry_delay => 100, (ms, default 0)
                verbose     => 1, (default 0)
                keep_alive  => 1, (default 0)
                agent       => 'Service Monkey', (default REST-Consumer/$VERSION)
                ua          => My::UserAgent->new,
                auth => {
                        type => 'basic',
                        username => 'yep',
                        password => 'nope',
                },
        );

Methods

get ( path => PATH, params => [] )

Send a GET request to the given path with the given arguments

        my $deserialized_result = $client->get(
                path => '/path/to/resource',
                params => {
                        field => value,
                        field2 => value2,
                },
        );

the 'params' arg can be a hash ref or array ref, depending on whether you need multiple instances of the same key

        my $deserialized_result = $client->get(
                path => '/path/to/resource',
                params => [
                        field => value,
                        field => value2,
                        field => value3,
                ]
        );

If ->get encounters an error code (400, 500, etc) it will treat this as an exception, and raise it (or return undef if $REST::Consumer::raise_exceptions has been explicitly set to 0 - but you shouldn't do this; you should either wrap the entire invocation in an eval block, or use handlers below to control the way REST::Consumer responds to exceptions.)

By default, ->get will attempt to deserialize the response body, and the deserialized structure will be its return value. If the body cannot be deserialized (e.g. if it is a plaintext document) the body will be returned (decoded from whatever transfer encoding it may have been encoded with, but not otherwise deserialized).

You can also specify a 'handlers' argument to ->get. This argument should be a hashref of <status, coderef> pairs. Handlers are used to react to a particular HTTP response code or set of response codes. If a handler matches the HTTP response, the return value of ->get will be the return value of that handler. This allows you to return a data structure of your choice, even in case of HTTP errors.

The status codes consist of either 3-digit scalars, such as 404 or '418', or a three-character response class, such as '2xx' or '5xx'. If an HTTP response returns a status code, a handler with that code will be looked for; if none is found, a handler with a wildcard code will then be looked for. If neither is present, execution will proceed as specified above.

A handler coderef is invoked with a single argument representing a handle to the handler's invocation -- $h in all the examples below. $h has several methods which can be used to access the request and response. The handler should return data, which will be presented as the return value of the ->get operation.

A handler can also return flow-control objects. If a flow-control object is returned instead of a regular object or scalar, the flow of the request processing will be altered. These flow-control objects are instantiated via methods on $h; valid flow control objects are $h->retry, $h->fail, and $h->default. For instance, a handler can return $h->default to proceed as if the handler code had not been specified. In that case, the value returned by ->get will be the response's deserialized content (or an exception, depending on the request's status code).

Here is an example of handlers being specified and returning values.

  # Obtain a welcome message from /welcome-message.
  my $custom_deserialized_result = $client->get(
     path => '/welcome-message',
     ...
     handlers => {
       2xx => sub {
         my ($h) = @_; # $h is a response handler invocation.
         if ($h->response_parseable) { # true if it's pareseable JSON
           return $h->parsed_response->{message};
           # ->parsed_response will throw an exception
           # if the response is not parseable
         } else {
           if ($h->response->content_type =~ qr{text/plain}) {
             # ->response_body is the unparsed body.
             # it is always available.
             return $h->response_body;
           } else {
             return $h->fail;
             # Returning $h->fail will invoke the standard failure mechanism,
             #   which will raise an exception or return undef, depending on
             #   the package configuration ($REST::Consumer::throw_exceptions
             #   is true by default - you ought to leave it that way, and use
             #   handlers to deal with exceptions, instead).
           }
         }
       },
       403 => sub { return 'Go away!'; },
       404 => sub { 'You're traveling through another dimension,' .
                    ' a dimension not only of sight and sound but of mind.' },
       418 => sub { return "I'm a little teapot, short and stout!" },
       420 => sub {  # (nonstandard status code / Twitter rate limiting).
         my ($h) = @_;
         return $h->retry;
         # Returning $h->retry will cause the request to be retried.
         # This operation respects the number of retries and the retry delay
         # specified at the REST::Consumer instantiation.
       },
       2xx => sub {
         my ($h) = @_;

         # (assuming a $self from enclosing scope)
         # ->response and ->request are HTTP::Response and HTTP::Request objects
         $self->log("Welcome message successfully located for %s", $h->request->uri);

         # Returning $h->default will resume normal REST::Consumer processing.
         # Depending on what sort of response this is, that may result in
         #   returning the response's content, retrying the request, or throwing
         #   an exception (or returning undef, if $REST::Consumer::ThrowExceptions
         #   is false.)
         return $h->default;
       },
     },
  );
post (path => PATH, params => [key => value, key => value], content => {...} )

Send a POST request with the given path, params, and content. The content must be a data structure that can be serialized to JSON.

        # content is serialized to json by default
        my $deserialized_result = $client->post(
                path => '/path/to/resource',
                content => { field => value }
        );


        # if you don't want it serialized, specify another content type
        my $deserialized_result = $client->post(
                path => '/path/to/resource',
                content => { field => value }
                content_type => 'multipart/form-data',
        );

        # you can also specify headers if needed
        my $deserialized_result = $client->post(
                path => '/path/to/resource',
                headers => [
                        'x-custom-header' => 'monkeys',
                ],
                content => { field => value }
        );

->post() returns the deserialized result by default. It also allows you to specify handlers. See the documentation for ->get().

delete (path => PATH, params => [])

Send a DELETE request to the given path with the given arguments.

        my $result = $client->delete(
                path => '/path/to/resource',
                params => [
                        field => value,
                        field2 => value2,
                ]
        );

->delete() returns the deserialized result by default. It also allows you to specify handlers. See the documentation for ->get().

get_response (path => PATH, params => [key => value, key => value], headers => [key => value,....], content => {...}, handlers => {...}, method => METHOD )

Send a request with path, params, and content, using the specified method, e.g. POST. But you already have a method ->post, so maybe the method is something like PROPFIND, BREW, or WHEN.

By default, ->get_response will return an HTTP::Response object. ->get_response also allows you to specify handlers. See the documentation for ->get().

        my $response_obj = $client->get_response(
                method => 'GET',
                path   => '/path/to/resource',
                headers => [
                        'x-header' => 'header',
                ],
                params => [
                        field => value,
                        field2 => value2,
                ],
    handlers => {},
        );

(N.B. If specifying method the methods BREW or WHEN, it is recommended that you supply a handler for the HTTP 418 response. See RFC 2324 for more information.)

get_processed_response (path => PATH, params => [key => value, key => value], headers => [key => value,....], content => {...}, handlers => {...}, method => METHOD)

Send a request with path, params, and content, using the specified method, and get the deserialized content back. ->get_processed_response() also allows you to specify handlers. See the documentation for ->get().

If handlers for the resposnse have been specified, the return value will be whatever the handler returns. If the content is JSON, it will be parsed. If the content is not JSON, it will be returned as a string.

get_http_request ( path => PATH, params => [PARAMS], headers => [HEADERS], content => [], method => '' )

Get an HTTP::Request object for the given input.

(The request will not actually be issued.)