File Coverage

blib/lib/Future/HTTP.pm
Criterion Covered Total %
statement 19 29 65.5
branch 3 6 50.0
condition 0 3 0.0
subroutine 3 5 60.0
pod 2 3 66.6
total 27 46 58.7


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