]> Dogcows Code - chaz/p5-HTTP-AnyUA/blob - README.md
add README
[chaz/p5-HTTP-AnyUA] / README.md
1 # NAME
2
3 HTTP::AnyUA - An HTTP user agent programming interface unification layer
4
5 # VERSION
6
7 version 0.900
8
9 # SYNOPSIS
10
11 my $any_ua = HTTP::AnyUA->new(ua => LWP::UserAgent->new);
12 # OR: my $any_ua = HTTP::AnyUA->new(ua => Furl->new);
13 # OR: my $any_ua = HTTP::AnyUA->new(ua => HTTP::Tiny->new);
14 # etc...
15
16 my $response = $any_ua->get('http://www.example.com/');
17
18 print "$response->{status} $response->{reason}\n";
19
20 while (my ($k, $v) = each %{$response->{headers}}) {
21 for (ref $v eq 'ARRAY' ? @$v : $v) {
22 print "$k: $_\n";
23 }
24 }
25
26 print $response->{content} if length $response->{content};
27
28 ### Non-blocking user agents cause Future objects to be returned:
29
30 my $any_ua = HTTP::AnyUA->new(ua => HTTP::Tiny->new, response_is_future => 1);
31 # OR: my $any_ua = HTTP::AnyUA->new(ua => 'AnyEvent::HTTP');
32 # OR: my $any_ua = HTTP::AnyUA->new(ua => Mojo::UserAgent->new);
33 # etc...
34
35 my $future = $any_ua->get('http://www.example.com/');
36
37 $future->on_done(sub {
38 my $response = shift;
39
40 print "$response->{status} $response->{reason}\n";
41
42 while (my ($k, $v) = each %{$response->{headers}}) {
43 for (ref $v eq 'ARRAY' ? @$v : $v) {
44 print "$k: $_\n";
45 }
46 }
47
48 print $response->{content} if length $response->{content};
49 });
50
51 $future->on_fail(sub { print STDERR "Oh no!!\n" });
52
53 # DESCRIPTION
54
55 This module provides a small wrapper for unifying the programming interfaces of several different
56 actual user agents (HTTP clients) under one **familiar** interface.
57
58 Rather than providing yet another programming interface for you to learn, HTTP::AnyUA follows the
59 [HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny) interface. This also means that you can plug in any supported HTTP client
60 ([LWP::UserAgent](https://metacpan.org/pod/LWP::UserAgent), [Furl](https://metacpan.org/pod/Furl), etc.) and use it as if it were [HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny).
61
62 There are a lot of great HTTP clients available for Perl, each with different goals, different
63 feature sets, and of course different programming interfaces! If you're an end user, you can just
64 pick one of these clients according to the needs of your project (or personal preference). But if
65 you're writing a module that needs to interface with a web server (like perhaps a RESTful API
66 wrapper) and you want your users to be able to use whatever HTTP client they want, HTTP::AnyUA can
67 help you support that!
68
69 It's a good idea to let the end user pick whatever HTTP client they want to use, because they're the
70 one who knows the requirements of their application or script. If you're writing an event-driven
71 application, you'll need to use a non-blocking user agent like [Mojo::UserAgent](https://metacpan.org/pod/Mojo::UserAgent). If you're writing
72 a simple command-line script, you may decide that your priority is to minimize dependencies and so
73 may want to go with [HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny).
74
75 Unfortunately, many modules on CPAN are hardcoded to work with specific HTTP clients, leaving the
76 end user unable to use the HTTP client that would be best for them. Although the end user won't --
77 or at least doesn't need to -- use HTTP::AnyUA directly, they will benefit from client choice if
78 their third-party modules use HTTP::AnyUA or something like it.
79
80 The primary goal of HTTP::AnyUA is to make it easy for module developers to write HTTP code once
81 that can work with any HTTP client the end user may decide to plug in. A secondary goal is to make
82 it easy for anyone to add support for new or yet-unsupported user agents.
83
84 # ATTRIBUTES
85
86 ## ua
87
88 Get the user agent that was passed to ["new"](#new).
89
90 ## response\_is\_future
91
92 Get and set whether or not responses are [Future](https://metacpan.org/pod/Future) objects.
93
94 ## backend
95
96 Get the backend instance. You normally shouldn't need this.
97
98 # METHODS
99
100 ## new
101
102 $any_ua = HTTP::AnyUA->new(ua => $user_agent, %attr);
103 $any_ua = HTTP::AnyUA->new($user_agent, %attr);
104
105 Construct a new HTTP::AnyUA.
106
107 ## request
108
109 $response = $any_ua->request($method, $url);
110 $response = $any_ua->request($method, $url, \%options);
111
112 Make a [request](#the-request), get a [response](#the-response).
113
114 Compare to ["request" in HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny#request).
115
116 ## get, head, put, post, delete
117
118 $response = $any_ua->get($url);
119 $response = $any_ua->get($url, \%options);
120 $response = $any_ua->head($url);
121 $response = $any_ua->head($url, \%options);
122 # etc.
123
124 Shortcuts for ["request"](#request) where the method is the method name rather than the first argument.
125
126 Compare to ["get|head|put|post|delete" in HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny#get-head-put-post-delete).
127
128 ## post\_form
129
130 $response = $any_ua->post_form($url, $formdata);
131 $response = $any_ua->post_form($url, $formdata, \%options);
132
133 Does a `POST` request with the form data encoded and sets the `Content-Type` header to
134 `application/x-www-form-urlencoded`.
135
136 Compare to ["post\_form" in HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny#post_form).
137
138 ## mirror
139
140 $response = $http->mirror($url, $filepath, \%options);
141 if ($response->{success}) {
142 print "$filepath is up to date\n";
143 }
144
145 Does a `GET` request and saves the downloaded document to a file. If the file already exists, its
146 timestamp will be sent using the `If-Modified-Since` request header (which you can override). If
147 the server responds with a `304` (Not Modified) status, the `success` field will be true; this is
148 usually only the case for `2XX` statuses. If the server responds with a `Last-Modified` header,
149 the file will be updated to have the same modification timestamp.
150
151 Compare to ["mirror" in HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny#mirror). This version differs slightly in that this returns internal
152 exception responses (for cases like being unable to write the file locally, etc.) rather than
153 actually throwing the exceptions. The reason for this is that exceptions as responses are easier to
154 deal with for non-blocking HTTP clients, and the fact that this method throws exceptions in
155 [HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny) seems like an inconsistency in its interface.
156
157 ## register\_backend
158
159 HTTP::AnyUA->register_backend($user_agent_package => $backend_package);
160 HTTP::AnyUA->register_backend('MyAgent' => 'MyBackend'); # HTTP::AnyUA::Backend::MyBackend
161 HTTP::AnyUA->register_backend('LWP::UserAgent' => '+SpecialBackend'); # SpecialBackend
162
163 Register a backend for a new user agent type or override a default backend. Backend packages are
164 relative to the `HTTP::AnyUA::Backend::` namespace unless prefixed with a `+`.
165
166 If you only need to set a backend as a one-off thing, you could also pass an instantiated backend to
167 ["new"](#new).
168
169 # SUPPORTED USER AGENTS
170
171 - [AnyEvent::HTTP](https://metacpan.org/pod/AnyEvent::HTTP)
172 - [Furl](https://metacpan.org/pod/Furl)
173 - [HTTP::AnyUA](https://metacpan.org/pod/HTTP::AnyUA) - a little bit meta, but why not?
174 - [HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny)
175 - [LWP::UserAgent](https://metacpan.org/pod/LWP::UserAgent)
176 - [Mojo::UserAgent](https://metacpan.org/pod/Mojo::UserAgent)
177 - [Net::Curl::Easy](https://metacpan.org/pod/Net::Curl::Easy)
178
179 Any HTTP client that inherits from one of these in a well-behaved manner should also be supported.
180
181 Of course, there are many other HTTP clients on CPAN that HTTP::AnyUA doesn't yet support. I'm more
182 than happy to help add support for others, so send me a message if you know of an HTTP client that
183 needs support. See [HTTP::AnyUA::Backend](https://metacpan.org/pod/HTTP::AnyUA::Backend) for how to write support for a new HTTP client.
184
185 # NON-BLOCKING USER AGENTS
186
187 HTTP::AnyUA tries to target the [HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny) interface, which is a blocking interface. This means
188 that when you call ["request"](#request), it is supposed to not return until either the response is received
189 or an error occurs. This doesn't jive well with non-blocking HTTP clients which expect the flow to
190 reenter an event loop so that the request can complete concurrently.
191
192 In order to reconcile this, a [Future](https://metacpan.org/pod/Future) will be returned instead of the normal hashref response if
193 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
194 [Future](https://metacpan.org/pod/Future) object may be used to set up callbacks that will be called when the request is completed.
195 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).
196
197 This is typically okay for the end user; since they're the one who chose which HTTP client to use in
198 the first place, they should know whether they should expect a [Future](https://metacpan.org/pod/Future) or a direct response when
199 they make an HTTP request, but it does add some burden on you as a module writer because if you ever
200 need to examine the response, you may need to write code like this:
201
202 my $resp = $any_ua->get('http://www.perl.org/');
203
204 if ($any_ua->response_is_future) {
205 $resp->on_done(sub {
206 my $real_resp = shift;
207 handle_response($real_resp);
208 });
209 }
210 else {
211 handle_response($resp); # response is the real response already
212 }
213
214 This actually isn't too annoying to deal with in practice, but you can avoid it if you like by
215 forcing the response to always be a [Future](https://metacpan.org/pod/Future). Just set the ["response\_is\_future"](#response_is_future) attribute. Then
216 you don't need to do an if-else because the response will always be the same type:
217
218 $any_ua->response_is_future(1);
219
220 my $resp = $any_ua->get('http://www.perl.org/');
221
222 $resp->on_done(sub { # response is always a Future
223 my $real_resp = shift;
224 handle_response($real_resp);
225 });
226
227 Note that this doesn't make a blocking HTTP client magically non-blocking. The call to ["request"](#request)
228 will still block if the client is blocking, and your "done" callback will simply be fired
229 immediately. But this does let you write the same code in your module and have it work regardless of
230 whether the underlying HTTP client is blocking or non-blocking.
231
232 The default behavior is to return a direct hashref response if the HTTP client is blocking and
233 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
234 `response_is_future`, and you should also consider whether you want to expose the possibility of
235 either type of response or always returning [Future](https://metacpan.org/pod/Future) objects to the end user of your module. It
236 doesn't matter for users who choose non-blocking HTTP clients because they will be using [Future](https://metacpan.org/pod/Future)
237 objects either way, but users who know they are using a blocking HTTP client may appreciate not
238 having to deal with [Future](https://metacpan.org/pod/Future) objects at all.
239
240 # FREQUENTLY ASKED QUESTIONS
241
242 ## How do I set up proxying, SSL, cookies, timeout, etc.?
243
244 HTTP::AnyUA provides a common interface for _using_ HTTP clients, not for instantiating or
245 configuring them. Proxying, SSL, and other custom settings can be configured directly through the
246 underlying HTTP client; see the documentation for your particular user agent to learn how to
247 configure these things.
248
249 [AnyEvent::HTTP](https://metacpan.org/pod/AnyEvent::HTTP) is a bit of a special case because there is no instantiated object representing
250 the client. For this particular user agent, you can configure the backend to pass a default set of
251 options whenever it calls `http_request`. See ["options" in HTTP::AnyUA::Backend::AnyEvent::HTTP](https://metacpan.org/pod/HTTP::AnyUA::Backend::AnyEvent::HTTP#options):
252
253 $any_ua->backend->options({recurse => 5, timeout => 15});
254
255 If you are a module writer, you should probably receive a user agent from your end user and leave
256 this type of configuration up to them.
257
258 ## Why use HTTP::AnyUA instead of some other HTTP client?
259
260 Maybe you shouldn't. If you're an end user writing a script or application, you can just pick the
261 HTTP client that suits you best and use it. For example, if you're writing a [Mojolicious](https://metacpan.org/pod/Mojolicious) app,
262 you're not going wrong by using [Mojo::UserAgent](https://metacpan.org/pod/Mojo::UserAgent); it's loaded with features and is well-integrated
263 with that particular environment.
264
265 As an end user, you _could_ wrap the HTTP client you pick in an HTTP::AnyUA object, but the only
266 reason to do this is if you prefer using the [HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny) interface.
267
268 The real benefit of HTTP::AnyUA (or something like it) is if module writers use it to allow end
269 users of their modules to be able to plug in whatever HTTP client they want. For example, a module
270 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)
271 is essentially useless for non-blocking applications. If the same hypothetical module had been
272 written using HTTP::AnyUA then it would be useful in any scenario.
273
274 ## Why use the HTTP::Tiny interface?
275
276 The [HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny) interface is simple but provides all the essential functionality needed for
277 a capable HTTP client and little more. That makes it easy to provide an implementation for, and it
278 also makes it straightforward for module authors to use.
279
280 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
281 non-blocking modules and applications.
282
283 # SPECIFICATION
284
285 This section specifies a standard set of data structures that can be used to make a request and get
286 a response from a user agent. This is the specification HTTP::AnyUA uses for its programming
287 interface. It is heavily based on [HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny)'s interface, and parts of this specification were
288 adapted or copied verbatim from that module's documentation. The intent is for this specification to
289 be written such that [HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny) is already a compliant implementor of the specification (at least
290 as of the specification's publication date).
291
292 ## The Request
293
294 A request is a tuple of the form `(Method, URL)` or `(Method, URL, Options)`.
295
296 ### Method
297
298 Method **MUST** be a string representing the HTTP verb. This is commonly `"GET"`, `"POST"`,
299 `"HEAD"`, `"DELETE"`, etc.
300
301 ### URL
302
303 URL **MUST** be a string representing the remote resource to be acted upon. The URL **MUST** have
304 unsafe characters escaped and international domain names encoded before being passed to the user
305 agent. A user agent **MUST** generated a `"Host"` header based on the URL in accordance with RFC
306 2616; a user agent **MAY** throw an error if a `"Host"` header is given with the ["headers"](#headers).
307
308 ### Options
309
310 Options, if present, **MUST** be a hash reference containing zero or more of the following keys with
311 appropriate values. A user agent **MAY** support more options than are specified here.
312
313 #### headers
314
315 The value for the `headers` key **MUST** be a hash reference containing zero or more HTTP header
316 names (as keys) and header values. The value for a header **MUST** be either a string containing the
317 header value OR an array reference where each item is a string. If the value for a header is an
318 array reference, the user agent **MUST** output the header multiple times with each value in the
319 array.
320
321 User agents **MAY** may add headers, but **SHOULD NOT** replace user-specified headers unless
322 otherwise documented.
323
324 #### content
325
326 The value for the `content` key **MUST** be a string OR a code reference. If the value is a string,
327 its contents will be included with the request as the body. If the value is a code reference, the
328 referenced code will be called iteratively to produce the body of the request, and the code **MUST**
329 return an empty string or undef value to indicate the end of the request body. If the value is
330 a code reference, a user agent **SHOULD** use chunked transfer encoding if it supports it, otherwise
331 a user agent **MAY** completely drain the code of content before sending the request.
332
333 #### data\_callback
334
335 The value for the `data_callback` key **MUST** be a code reference that will be called zero or more
336 times, once for each "chunk" of response body received. A user agent **MAY** send the entire response
337 body in one call. The referenced code **MUST** be given two arguments; the first is a string
338 containing a chunk of the response body, the second is an in-progress [response](#the-response).
339
340 ## The Response
341
342 A response **MUST** be a hash reference containg some required keys and values. A response **MAY**
343 contain some optional keys and values.
344
345 ### success
346
347 A response **MUST** include a `success` key, the value of which is a boolean indicating whether or
348 not the request is to be considered a success (true is a success). Unless otherwise documented,
349 a successful result means that the operation returned a 2XX status code.
350
351 ### url
352
353 A response **MUST** include a `url` key, the value of which is the URL that provided the response.
354 This is the URL used in the request unless there were redirections, in which case it is the last URL
355 queried in a rediretion chain.
356
357 ### status
358
359 A response **MUST** include a `status` key, the value of which is the HTTP status code of the
360 response. If an internal exception occurs (e.g. connection error), then the status code **MUST** be
361 `599`.
362
363 ### reason
364
365 A response **MUST** include a `reason` key, the value of which is the response phrase returned by
366 the server OR "Internal Exception" if an internal exception occurred.
367
368 ### content
369
370 A response **MAY** include a `content` key, the value of which is the response body returned by the
371 server OR the text of the exception if an internal exception occurred. This field **MUST** be missing
372 or empty if the server provided no response OR if the body was already provided via
373 ["data\_callback"](#data_callback).
374
375 ### headers
376
377 A response **SHOULD** include a `headers` key, the value of which is a hash reference containing
378 zero or more HTTP header names (as keys) and header values. Keys **MUST** be lowercased. The value
379 for a header **MUST** be either a string containing the header value OR an array reference where each
380 item is the value of one of the repeated headers.
381
382 ### redirects
383
384 A response **MAY** include a `redirects` key, the value of which is an array reference of one or
385 more responses from redirections that occurred to fulfill the current request, in chronological
386 order.
387
388 # ENVIRONMENT
389
390 - `PERL_HTTP_ANYUA_DEBUG` - If 1, print some info useful for debugging to `STDERR`.
391
392 # CAVEATS
393
394 Not all HTTP clients implement the same features or in the same ways. While the point of HTTP::AnyUA
395 is to hide those differences, you may notice some (hopefully) _insignificant_ differences when
396 plugging in different clients. For example, [LWP::UserAgent](https://metacpan.org/pod/LWP::UserAgent) sets some headers on the response such
397 as `client-date` and `client-peer` that won't appear when using other clients. Little differences
398 like these probably aren't big deal. Other differences may be a bigger deal, depending on what's
399 important to you. For example, some clients (like [HTTP::Tiny](https://metacpan.org/pod/HTTP::Tiny)) may do chunked transfer encoding in
400 situations where other clients won't (probably because they don't support it). It's not a goal of
401 this project to eliminate _all_ of the differences, but if you come across a difference that is
402 significant enough that you think you need to detect the user agent and write special logic, I would
403 like to learn about your use case.
404
405 # SEE ALSO
406
407 These modules share similar goals or provide overlapping functionality:
408
409 - [Future::HTTP](https://metacpan.org/pod/Future::HTTP)
410 - [HTTP::Any](https://metacpan.org/pod/HTTP::Any)
411 - [HTTP::Tinyish](https://metacpan.org/pod/HTTP::Tinyish)
412 - [Plient](https://metacpan.org/pod/Plient)
413
414 # BUGS
415
416 Please report any bugs or feature requests on the bugtracker website
417 [https://github.com/chazmcgarvey/HTTP-AnyUA/issues](https://github.com/chazmcgarvey/HTTP-AnyUA/issues)
418
419 When submitting a bug or request, please include a test-file or a
420 patch to an existing test-file that illustrates the bug or desired
421 feature.
422
423 # AUTHOR
424
425 Charles McGarvey <chazmcgarvey@brokenzipper.com>
426
427 # COPYRIGHT AND LICENSE
428
429 This software is copyright (c) 2017 by Charles McGarvey.
430
431 This is free software; you can redistribute it and/or modify it under
432 the same terms as the Perl 5 programming language system itself.
This page took 0.050322 seconds and 5 git commands to generate.