Release HTTP-AnyUA 0.901 v0.901
authorCharles McGarvey <chazmcgarvey@brokenzipper.com>
Mon, 6 Nov 2017 05:06:34 +0000 (22:06 -0700)
committerCharles McGarvey <chazmcgarvey@brokenzipper.com>
Mon, 6 Nov 2017 05:06:34 +0000 (22:06 -0700)
  * Add middleware
  * Fix up some documentation issues

.travis.yml
Changes
README.md

index c0fa429abd27371c6e0389f14cf556b96c0f37d1..e90dbdc2a54a00fa9fd694041c217e3dfcd77081 100644 (file)
@@ -1,6 +1,7 @@
 sudo: false
 language: perl
 perl:
+   - '5.26'
    - '5.24'
    - '5.22'
    - '5.20'
diff --git a/Changes b/Changes
index 8dd6ef9673bf93a774928ea250f520cb8ecec689..4e7350ebb1fb97a57a7d0d36a1b5d30463e70bbf 100644 (file)
--- a/Changes
+++ b/Changes
@@ -2,6 +2,11 @@ Revision history for HTTP-AnyUA.
 
 {{$NEXT}}
 
+0.901     2017-11-05 22:05:57-07:00 MST7MDT
+
+  * Add middleware
+  * Fix up some documentation issues
+
 0.900     2017-03-11 18:28:59-07:00 MST7MDT
 
   * Initial release
index de99ed5527cc3728d27240d958d6b0f3c4bb5b01..c5724e6bcedf9edef2d53adc786a0742f14c12b5 100644 (file)
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@ HTTP::AnyUA - An HTTP user agent programming interface unification layer
 
 # VERSION
 
-version 0.900
+version 0.901
 
 # SYNOPSIS
 
@@ -154,6 +154,27 @@ actually throwing the exceptions. The reason for this is that exceptions as resp
 deal with for non-blocking HTTP clients, and the fact that this method throws exceptions in
 [HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny) seems like an inconsistency in its interface.
 
+## apply\_middleware
+
+    $any_ua->apply_middleware($middleware_package);
+    $any_ua->apply_middleware($middleware_package, %args);
+    $any_ua->apply_middleware($middleware_obj);
+
+Wrap the backend with some new middleware. Middleware packages are relative to the
+`HTTP::AnyUA::Middleware::` namespace unless prefixed with a `+`.
+
+This effectively replaces the ["backend"](#backend) with a new object that wraps the previous backend.
+
+This can be used multiple times to add multiple layers of middleware, and order matters. The last
+middleware applied is the first one to see the request and last one to get the response. For
+example, if you apply middleware that does logging and middleware that does caching (and
+short-circuits on a cache hit), applying your logging middleware _first_ will cause only cache
+misses to be logged whereas applying your cache middleware first will allow all requests to be
+logged.
+
+See [HTTP::AnyUA::Middleware](https://metacpan.org/pod/HTTP::AnyUA::Middleware) for more information about what middleware is and how to write your
+own middleware.
+
 ## register\_backend
 
     HTTP::AnyUA->register_backend($user_agent_package => $backend_package);
@@ -166,120 +187,6 @@ relative to the `HTTP::AnyUA::Backend::` namespace unless prefixed with a `+`.
 If you only need to set a backend as a one-off thing, you could also pass an instantiated backend to
 ["new"](#new).
 
-# SUPPORTED USER AGENTS
-
-- [AnyEvent::HTTP](https://metacpan.org/pod/AnyEvent::HTTP)
-- [Furl](https://metacpan.org/pod/Furl)
-- [HTTP::AnyUA](https://metacpan.org/pod/HTTP::AnyUA) - a little bit meta, but why not?
-- [HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny)
-- [LWP::UserAgent](https://metacpan.org/pod/LWP::UserAgent)
-- [Mojo::UserAgent](https://metacpan.org/pod/Mojo::UserAgent)
-- [Net::Curl::Easy](https://metacpan.org/pod/Net::Curl::Easy)
-
-Any HTTP client that inherits from one of these in a well-behaved manner should also be supported.
-
-Of course, there are many other HTTP clients on CPAN that HTTP::AnyUA doesn't yet support. I'm more
-than happy to help add support for others, so send me a message if you know of an HTTP client that
-needs support. See [HTTP::AnyUA::Backend](https://metacpan.org/pod/HTTP::AnyUA::Backend) for how to write support for a new HTTP client.
-
-# NON-BLOCKING USER AGENTS
-
-HTTP::AnyUA tries to target the [HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny) interface, which is a blocking interface. This means
-that when you call ["request"](#request), it is supposed to not return until either the response is received
-or an error occurs. This doesn't jive well with non-blocking HTTP clients which expect the flow to
-reenter an event loop so that the request can complete concurrently.
-
-In order to reconcile this, a [Future](https://metacpan.org/pod/Future) will be returned instead of the normal hashref response if
-the wrapped HTTP client is non-blocking (such as [Mojo::UserAgent](https://metacpan.org/pod/Mojo::UserAgent) or [AnyEvent::HTTP](https://metacpan.org/pod/AnyEvent::HTTP)). This
-[Future](https://metacpan.org/pod/Future) object may be used to set up callbacks that will be called when the request is completed.
-You can call ["response\_is\_future"](#response_is_future) to know if the response is or will be a [Future](https://metacpan.org/pod/Future).
-
-This is typically okay for the end user; since they're the one who chose which HTTP client to use in
-the first place, they should know whether they should expect a [Future](https://metacpan.org/pod/Future) or a direct response when
-they make an HTTP request, but it does add some burden on you as a module writer because if you ever
-need to examine the response, you may need to write code like this:
-
-    my $resp = $any_ua->get('http://www.perl.org/');
-
-    if ($any_ua->response_is_future) {
-        $resp->on_done(sub {
-            my $real_resp = shift;
-            handle_response($real_resp);
-        });
-    }
-    else {
-        handle_response($resp);     # response is the real response already
-    }
-
-This actually isn't too annoying to deal with in practice, but you can avoid it if you like by
-forcing the response to always be a [Future](https://metacpan.org/pod/Future). Just set the ["response\_is\_future"](#response_is_future) attribute. Then
-you don't need to do an if-else because the response will always be the same type:
-
-    $any_ua->response_is_future(1);
-
-    my $resp = $any_ua->get('http://www.perl.org/');
-
-    $resp->on_done(sub {            # response is always a Future
-        my $real_resp = shift;
-        handle_response($real_resp);
-    });
-
-Note that this doesn't make a blocking HTTP client magically non-blocking. The call to ["request"](#request)
-will still block if the client is blocking, and your "done" callback will simply be fired
-immediately. But this does let you write the same code in your module and have it work regardless of
-whether the underlying HTTP client is blocking or non-blocking.
-
-The default behavior is to return a direct hashref response if the HTTP client is blocking and
-a [Future](https://metacpan.org/pod/Future) if the client is non-blocking. It's up to you to decide whether or not to set
-`response_is_future`, and you should also consider whether you want to expose the possibility of
-either type of response or always returning [Future](https://metacpan.org/pod/Future) objects to the end user of your module. It
-doesn't matter for users who choose non-blocking HTTP clients because they will be using [Future](https://metacpan.org/pod/Future)
-objects either way, but users who know they are using a blocking HTTP client may appreciate not
-having to deal with [Future](https://metacpan.org/pod/Future) objects at all.
-
-# FREQUENTLY ASKED QUESTIONS
-
-## How do I set up proxying, SSL, cookies, timeout, etc.?
-
-HTTP::AnyUA provides a common interface for _using_ HTTP clients, not for instantiating or
-configuring them. Proxying, SSL, and other custom settings can be configured directly through the
-underlying HTTP client; see the documentation for your particular user agent to learn how to
-configure these things.
-
-[AnyEvent::HTTP](https://metacpan.org/pod/AnyEvent::HTTP) is a bit of a special case because there is no instantiated object representing
-the client. For this particular user agent, you can configure the backend to pass a default set of
-options whenever it calls `http_request`. See ["options" in HTTP::AnyUA::Backend::AnyEvent::HTTP](https://metacpan.org/pod/HTTP::AnyUA::Backend::AnyEvent::HTTP#options):
-
-    $any_ua->backend->options({recurse => 5, timeout => 15});
-
-If you are a module writer, you should probably receive a user agent from your end user and leave
-this type of configuration up to them.
-
-## Why use HTTP::AnyUA instead of some other HTTP client?
-
-Maybe you shouldn't. If you're an end user writing a script or application, you can just pick the
-HTTP client that suits you best and use it. For example, if you're writing a [Mojolicious](https://metacpan.org/pod/Mojolicious) app,
-you're not going wrong by using [Mojo::UserAgent](https://metacpan.org/pod/Mojo::UserAgent); it's loaded with features and is well-integrated
-with that particular environment.
-
-As an end user, you _could_ wrap the HTTP client you pick in an HTTP::AnyUA object, but the only
-reason to do this is if you prefer using the [HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny) interface.
-
-The real benefit of HTTP::AnyUA (or something like it) is if module writers use it to allow end
-users of their modules to be able to plug in whatever HTTP client they want. For example, a module
-that implements an API wrapper that has a hard dependency on [LWP::UserAgent](https://metacpan.org/pod/LWP::UserAgent) or even [HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny)
-is essentially useless for non-blocking applications. If the same hypothetical module had been
-written using HTTP::AnyUA then it would be useful in any scenario.
-
-## Why use the HTTP::Tiny interface?
-
-The [HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny) interface is simple but provides all the essential functionality needed for
-a capable HTTP client and little more. That makes it easy to provide an implementation for, and it
-also makes it straightforward for module authors to use.
-
-Marrying the [HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny) interface with [Future](https://metacpan.org/pod/Future) gives us these benefits for both blocking and
-non-blocking modules and applications.
-
 # SPECIFICATION
 
 This section specifies a standard set of data structures that can be used to make a request and get
@@ -302,7 +209,7 @@ Method **MUST** be a string representing the HTTP verb. This is commonly `"GET"`
 
 URL **MUST** be a string representing the remote resource to be acted upon. The URL **MUST** have
 unsafe characters escaped and international domain names encoded before being passed to the user
-agent. A user agent **MUST** generated a `"Host"` header based on the URL in accordance with RFC
+agent. A user agent **MUST** generate a `"Host"` header based on the URL in accordance with RFC
 2616; a user agent **MAY** throw an error if a `"Host"` header is given with the ["headers"](#headers).
 
 ### Options
@@ -352,7 +259,7 @@ a successful result means that the operation returned a 2XX status code.
 
 A response **MUST** include a `url` key, the value of which is the URL that provided the response.
 This is the URL used in the request unless there were redirections, in which case it is the last URL
-queried in a rediretion chain.
+queried in a redirection chain.
 
 ### status
 
@@ -385,6 +292,120 @@ A response **MAY** include a `redirects` key, the value of which is an array ref
 more responses from redirections that occurred to fulfill the current request, in chronological
 order.
 
+# FREQUENTLY ASKED QUESTIONS
+
+## How do I set up proxying, SSL, cookies, timeout, etc.?
+
+HTTP::AnyUA provides a common interface for _using_ HTTP clients, not for instantiating or
+configuring them. Proxying, SSL, and other custom settings can be configured directly through the
+underlying HTTP client; see the documentation for your particular user agent to learn how to
+configure these things.
+
+[AnyEvent::HTTP](https://metacpan.org/pod/AnyEvent::HTTP) is a bit of a special case because there is no instantiated object representing
+the client. For this particular user agent, you can configure the backend to pass a default set of
+options whenever it calls `http_request`. See ["options" in HTTP::AnyUA::Backend::AnyEvent::HTTP](https://metacpan.org/pod/HTTP::AnyUA::Backend::AnyEvent::HTTP#options):
+
+    $any_ua->backend->options({recurse => 5, timeout => 15});
+
+If you are a module writer, you should probably receive a user agent from your end user and leave
+this type of configuration up to them.
+
+## Why use HTTP::AnyUA instead of some other HTTP client?
+
+Maybe you shouldn't. If you're an end user writing a script or application, you can just pick the
+HTTP client that suits you best and use it. For example, if you're writing a [Mojolicious](https://metacpan.org/pod/Mojolicious) app,
+you're not going wrong by using [Mojo::UserAgent](https://metacpan.org/pod/Mojo::UserAgent); it's loaded with features and is well-integrated
+with that particular environment.
+
+As an end user, you _could_ wrap the HTTP client you pick in an HTTP::AnyUA object, but the only
+reason to do this is if you prefer using the [HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny) interface.
+
+The real benefit of HTTP::AnyUA (or something like it) is if module writers use it to allow end
+users of their modules to be able to plug in whatever HTTP client they want. For example, a module
+that implements an API wrapper that has a hard dependency on [LWP::UserAgent](https://metacpan.org/pod/LWP::UserAgent) or even [HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny)
+is essentially useless for non-blocking applications. If the same hypothetical module had been
+written using HTTP::AnyUA then it would be useful in any scenario.
+
+## Why use the HTTP::Tiny interface?
+
+The [HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny) interface is simple but provides all the essential functionality needed for
+a capable HTTP client and little more. That makes it easy to provide an implementation for, and it
+also makes it straightforward for module authors to use.
+
+Marrying the [HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny) interface with [Future](https://metacpan.org/pod/Future) gives us these benefits for both blocking and
+non-blocking modules and applications.
+
+# SUPPORTED USER AGENTS
+
+- [AnyEvent::HTTP](https://metacpan.org/pod/AnyEvent::HTTP)
+- [Furl](https://metacpan.org/pod/Furl)
+- [HTTP::AnyUA](https://metacpan.org/pod/HTTP::AnyUA) - a little bit meta, but why not?
+- [HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny)
+- [LWP::UserAgent](https://metacpan.org/pod/LWP::UserAgent)
+- [Mojo::UserAgent](https://metacpan.org/pod/Mojo::UserAgent)
+- [Net::Curl::Easy](https://metacpan.org/pod/Net::Curl::Easy)
+
+Any HTTP client that inherits from one of these in a well-behaved manner should also be supported.
+
+Of course, there are many other HTTP clients on CPAN that HTTP::AnyUA doesn't yet support. I'm more
+than happy to help add support for others, so send me a message if you know of an HTTP client that
+needs support. See [HTTP::AnyUA::Backend](https://metacpan.org/pod/HTTP::AnyUA::Backend) for how to write support for a new HTTP client.
+
+# NON-BLOCKING USER AGENTS
+
+HTTP::AnyUA tries to target the [HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny) interface, which is a blocking interface. This means
+that when you call ["request"](#request), it is supposed to not return until either the response is received
+or an error occurs. This doesn't jive well with non-blocking HTTP clients which expect the flow to
+reenter an event loop so that the request can complete concurrently.
+
+In order to reconcile this, a [Future](https://metacpan.org/pod/Future) will be returned instead of the normal hashref response if
+the wrapped HTTP client is non-blocking (such as [Mojo::UserAgent](https://metacpan.org/pod/Mojo::UserAgent) or [AnyEvent::HTTP](https://metacpan.org/pod/AnyEvent::HTTP)). This
+[Future](https://metacpan.org/pod/Future) object may be used to set up callbacks that will be called when the request is completed.
+You can call ["response\_is\_future"](#response_is_future) to know if the response is or will be a [Future](https://metacpan.org/pod/Future).
+
+This is typically okay for the end user; since they're the one who chose which HTTP client to use in
+the first place, they should know whether they should expect a [Future](https://metacpan.org/pod/Future) or a direct response when
+they make an HTTP request, but it does add some burden on you as a module writer because if you ever
+need to examine the response, you may need to write code like this:
+
+    my $resp = $any_ua->get('http://www.perl.org/');
+
+    if ($any_ua->response_is_future) {
+        $resp->on_done(sub {
+            my $real_resp = shift;
+            handle_response($real_resp);
+        });
+    }
+    else {
+        handle_response($resp);     # response is the real response already
+    }
+
+This actually isn't too annoying to deal with in practice, but you can avoid it if you like by
+forcing the response to always be a [Future](https://metacpan.org/pod/Future). Just set the ["response\_is\_future"](#response_is_future) attribute. Then
+you don't need to do an if-else because the response will always be the same type:
+
+    $any_ua->response_is_future(1);
+
+    my $resp = $any_ua->get('http://www.perl.org/');
+
+    $resp->on_done(sub {            # response is always a Future
+        my $real_resp = shift;
+        handle_response($real_resp);
+    });
+
+Note that this doesn't make a blocking HTTP client magically non-blocking. The call to ["request"](#request)
+will still block if the client is blocking, and your "done" callback will simply be fired
+immediately. But this does let you write the same code in your module and have it work regardless of
+whether the underlying HTTP client is blocking or non-blocking.
+
+The default behavior is to return a direct hashref response if the HTTP client is blocking and
+a [Future](https://metacpan.org/pod/Future) if the client is non-blocking. It's up to you to decide whether or not to set
+`response_is_future`, and you should also consider whether you want to expose the possibility of
+either type of response or always returning [Future](https://metacpan.org/pod/Future) objects to the end user of your module. It
+doesn't matter for users who choose non-blocking HTTP clients because they will be using [Future](https://metacpan.org/pod/Future)
+objects either way, but users who know they are using a blocking HTTP client may appreciate not
+having to deal with [Future](https://metacpan.org/pod/Future) objects at all.
+
 # ENVIRONMENT
 
 - `PERL_HTTP_ANYUA_DEBUG` - If 1, print some info useful for debugging to `STDERR`.
@@ -395,7 +416,7 @@ Not all HTTP clients implement the same features or in the same ways. While the
 is to hide those differences, you may notice some (hopefully) _insignificant_ differences when
 plugging in different clients. For example, [LWP::UserAgent](https://metacpan.org/pod/LWP::UserAgent) sets some headers on the response such
 as `client-date` and `client-peer` that won't appear when using other clients. Little differences
-like these probably aren't big deal. Other differences may be a bigger deal, depending on what's
+like these probably aren't big deal. Other differences may be a bigger deal, depending on what's
 important to you. For example, some clients (like [HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny)) may do chunked transfer encoding in
 situations where other clients won't (probably because they don't support it). It's not a goal of
 this project to eliminate _all_ of the differences, but if you come across a difference that is
This page took 0.026955 seconds and 4 git commands to generate.