File Coverage

blib/lib/Future/HTTP.pm
Criterion Covered Total %
statement 25 35 71.4
branch 3 6 50.0
condition 0 3 0.0
subroutine 5 7 71.4
pod 2 3 66.6
total 35 54 64.8


line stmt bran cond sub pod time code
1             package Future::HTTP;
2 9     9   579591 use strict;
  9         80  
  9         290  
3 9     9   4783 use Filter::signatures;
  9         250541  
  9         70  
4 9     9   316 no warnings 'experimental::signatures';
  9         17  
  9         286  
5 9     9   47 use feature 'signatures';
  9         20  
  9         4072  
6              
7             =head1 NAME
8              
9             Future::HTTP - provide the most appropriate HTTP client with a Future API
10              
11             =head1 SYNOPSIS
12              
13             my $ua = Future::HTTP->new();
14             my $res = $ua->http_get('http://www.nethype.de/')->then(sub {
15             my( $body, $data ) = @_;
16             # ... handle the response
17             return $body
18             })->get();
19              
20             This module is a wrapper combining L with the API provided
21             by L. The backend used for the HTTP protocols
22             depends on whether one of the event loops is loaded.
23              
24             =head2 Supported event loops
25              
26             Currently, the following backends are supported:
27              
28             =over 4
29              
30             =item *
31              
32             L
33              
34             =item *
35              
36             L
37              
38             =item *
39              
40             L
41              
42             =item *
43              
44             L
45              
46             =item *
47              
48             L
49              
50             =back
51              
52             Support
53             is planned for L and L
54             but has not materialized yet.
55              
56             =cut
57              
58             our $VERSION = '0.14';
59              
60             our @loops;
61             push @loops, (
62             ['IO/Async.pm' => 'Future::HTTP::NetAsync' ],
63             ['Mojo/IOLoop.pm' => 'Future::HTTP::Mojo' ],
64             ['AnyEvent.pm' => 'Future::HTTP::AnyEvent'],
65             ['AE.pm' => 'Future::HTTP::AnyEvent'],
66             # POE support would be nice
67             # LWP::UserAgent support would be nice
68              
69             # A threaded backend would also be nice but likely brings in other
70             # interesting problems. How will we load this? We have two prerequisites
71             # now, threads.pm and HTTP::Tiny...
72             #['threads.pm' => 'Future::HTTP::Tiny::threaded' ],
73              
74             ['HTTP/Tiny/Paranoid.pm' => 'Future::HTTP::Tiny::Paranoid'],
75              
76             # The fallback, will always catch due to loading Future::HTTP
77             ['Future/HTTP.pm' => 'Future::HTTP::Tiny'],
78             );
79             our $implementation;
80             our $default = 'Future::HTTP::Tiny';
81              
82             =head1 METHODS
83              
84             =head2 C<< Future::HTTP->new() >>
85              
86             my $ua = Future::HTTP->new();
87              
88             Creates a new instance of the HTTP client.
89              
90             =cut
91              
92 0     0 1 0 sub new($factoryclass, @args) {
  0         0  
  0         0  
  0         0  
93 0   0     0 $implementation ||= $factoryclass->best_implementation();
94              
95             # return a new instance
96 0         0 $implementation->new(@args);
97             }
98              
99 7     7 0 654 sub best_implementation( $class, @candidates ) {
  7         21  
  7         14  
  7         13  
100              
101 7 50       44 if(! @candidates) {
102 7         35 @candidates = @loops;
103             };
104              
105             # Find the currently running/loaded event loop(s)
106             #use Data::Dumper;
107             #warn Dumper \%INC;
108             #warn Dumper \@candidates;
109             my @applicable_implementations = map {
110 9         38 $_->[1]
111             } grep {
112 7         26 $INC{$_->[0]}
  44         118  
113             } @candidates;
114              
115 7 50       31 if( ! @applicable_implementations ) {
116 0         0 @applicable_implementations = map {$_->[1]} @candidates;
  0         0  
117             }
118              
119             # Check which one we can load:
120 7         25 for my $impl (@applicable_implementations) {
121 7 50       473 if( eval "require $impl; 1" ) {
122 7         120 return $impl;
123             };
124             };
125              
126             # This will crash and burn, but that's how it is
127 0           return $default;
128             };
129              
130             =head2 C<< $ua->is_async() >>
131              
132             Returns true if the selected backend is asynchronous, false if it is
133             synchronous.
134              
135             =cut
136              
137             sub is_async {
138 0     0 1   die "method is_async must be overloaded by subclass\n";
139             }
140              
141             # We support the L API first
142              
143             =head2 C<< $ua->http_get($url, %options) >>
144              
145             my $res = $ua->http_get('http://example.com/',
146             headers => {
147             'Accept' => 'text/json',
148             },
149             )->then(sub {
150             my( $body, $headers ) = @_;
151             # ... handle the response
152             })->get;
153              
154             Retrieves the URL and returns the body and headers, like
155             the function in L.
156              
157             =head2 C<< $ua->http_head($url, %options) >>
158              
159             my $res = $ua->http_head('http://example.com/',
160             headers => {
161             'Accept' => 'text/json',
162             },
163             )->then(sub {
164             my( $body, $headers ) = @_;
165             ...
166             })->get;
167              
168             Retrieves the header of the URL and returns the headers,
169             like the function in L.
170              
171             =head2 C<< $ua->http_post($url, $body, %options) >>
172              
173             my $res = $ua->http_post('http://example.com/api',
174             '{token:"my_json_token"}',
175             headers => {
176             'Accept' => 'text/json',
177             },
178             )->then(sub {
179             my( $body, $headers ) = @_;
180             ...
181             })->get;
182              
183             Posts the content to the URL and returns the body and headers,
184             like the function in L.
185              
186             =head2 C<< $ua->http_request($method, $url, %options) >>
187              
188             my $res = $ua->http_request('PUT' => 'http://example.com/api',
189             headers => {
190             'Accept' => 'text/json',
191             },
192             body => '{token:"my_json_token"}',
193             )->then(sub {
194             my( $body, $headers ) = @_;
195             ...
196             })->get;
197              
198             Posts the content to the URL and returns the body and headers,
199             like the function in L.
200              
201             =head1 SEE ALSO
202              
203             L
204              
205             L for the details of the API
206              
207             =head1 REPOSITORY
208              
209             The public repository of this module is
210             L.
211              
212             =head1 SUPPORT
213              
214             The public support forum of this module is
215             L.
216              
217             =head1 BUG TRACKER
218              
219             Please report bugs in this module via the RT CPAN bug queue at
220             L
221             or via mail to L.
222              
223             =head1 AUTHOR
224              
225             Max Maischein C
226              
227             =head1 COPYRIGHT (c)
228              
229             Copyright 2016-2020 by Max Maischein C.
230              
231             =head1 LICENSE
232              
233             This module is released under the same terms as Perl itself.
234              
235             =cut
236              
237             # We should support more APIs like HTTP::Tiny, later
238             # See L.
239              
240             1;