root/lang/perl/WebService-Simple/branch/lwp-base/lib/WebService/Simple.pm @ 9695

Revision 9695, 6.8 kB (checked in by daisuke, 5 years ago)

lang/perl/WebService-Simple; Only require if not loaded

Line 
1# $Id$
2
3package WebService::Simple;
4use strict;
5use warnings;
6use base qw(LWP::UserAgent Class::Data::ConfigHash);
7use Class::Inspector;
8use Data::Dumper ();
9use Digest::MD5 ();
10use WebService::Simple::Response;
11use UNIVERSAL::require;
12
13our $VERSION = '0.00001';
14
15__PACKAGE__->config(
16    base_url => '',
17    cache => {
18        module => "Cache::FileCache",
19        args   => {
20        }
21    },
22    response_parser => {
23        module => "XML::Simple"
24    },
25);
26
27sub new
28{
29    my $class = shift;
30    my %args  = @_;
31    my $base_url     = delete $args{base_url} ||
32        $class->config->{base_url} ||
33        Carp::croak("base_url is required");
34    my $basic_params = delete $args{params} || delete $args{param} || {};
35    my $response_parser = delete $args{response_parser};
36    if (! $response_parser) {
37        my $config = $class->config->{response_parser};
38        if (! ref $config) {
39            $config = { module => $config };
40        }
41        my $module = $config->{module};
42        if ($module !~ s/^\+//) {
43            $module = __PACKAGE__ . "::Parser::$module";
44        }
45        if (! Class::Inspector->loaded($module)) {
46            $module->require or die;
47        }
48        $response_parser = $module->new( %{ $config->{args} || {} } );
49    };
50
51    my $cache = delete $args{cache};
52    if (! $cache || ref $cache eq 'HASH') {
53        my $config = ref $cache eq 'HASH' ? $cache : $class->config->{cache};
54        if ($config) {
55            if (! ref $config) {
56                $config = { module => $config };
57            }
58
59            my $module = $config->{module};
60            if (! Class::Inspector->loaded($module)) {
61                $module->require or die;
62            }
63            $cache = $module->new( $config->{hashref_args} ? $config->{args} : %{ $config->{args} } );
64        }
65    }
66
67    my $self = $class->SUPER::new(%args);
68    $self->{base_url} = URI->new($base_url);
69    $self->{basic_params} = $basic_params;
70    $self->{response_parser} = $response_parser;
71    $self->{cache} = $cache;
72    return $self;
73}
74
75sub base_url { $_[0]->{base_url} }
76sub basic_params { $_[0]->{basic_params} }
77sub response_parser { $_[0]->{response_parser} }
78sub cache { $_[0]->{cache} }
79
80sub __cache_get
81{
82    my $self  = shift;
83    my $cache = $self->cache;
84    return unless $cache;
85
86    my $key   = $self->__cache_key( shift );
87    return $cache->get( $key, @_ );
88}
89
90sub __cache_set
91{
92    my $self  = shift;
93    my $cache = $self->cache;
94    return unless $cache;
95
96    my $key   = $self->__cache_key( shift );
97    return $cache->set( $key, @_ );
98}
99
100sub __cache_remove
101{
102    my $self  = shift;
103    my $cache = $self->cache;
104    return unless $cache;
105
106    my $key   = $self->__cache_key( shift );
107    return $cache->remove( $key, @_ );
108}
109
110sub __cache_key
111{
112    my $self  = shift;
113    local $Data::Dumper::Indent   = 1;
114    local $Data::Dumper::Terse    = 1;
115    local $Data::Dumper::Sortkeys = 1;
116    return Digest::MD5::md5_hex( Data::Dumper::Dumper( $_[0] ) );
117}
118
119sub get
120{
121    my $self = shift;
122    my ($url, %extra, @headers);
123    if (ref $_[0] eq 'HASH') {
124        %extra = %{shift @_};
125    } else {
126        $url = shift @_;
127        if (ref $_[0] eq 'HASH') {
128            %extra = %{ shift @_ }
129        }
130    }
131
132    @headers = @_;
133
134    my $uri = URI->new($self->base_url);
135    $uri->path( $uri->path . $url) if $url;
136
137    # The url must be initialized with default parameters.
138
139    $uri->query_form( %{$self->basic_params}, %extra );
140
141    my $response;
142
143    $response = $self->__cache_get([$uri, @headers]);
144    if ($response) {
145        return $response;
146    }
147
148    $response = $self->SUPER::get($uri, @headers);
149    if (! $response->is_success) {
150        Carp::croak("request to $url failed");
151    }
152
153    $response = WebService::Simple::Response->new_from_response(
154        response => $response,
155        parser   => $self->response_parser
156    );
157    $self->__cache_set([$uri, @headers], $response);
158    return $response;
159
160}
161
162# まだできてない。
163sub post
164{
165    my ($self, $url, @params) = @_;
166
167    # default parameters must come *before* @params, so unshift instead
168    # of push
169    unshift @params, %{ $self->basic_params };
170    my $response = $self->SUPER::post($url, @params );
171
172    if (! $response->is_success) {
173        Carp::croak("request to $url failed");
174    }
175    return $response;
176}
177
1781;
179
180__END__
181
182=head1 NAME
183
184WebService::Simple - Simple Interface To Web Services APIs
185
186=head1 SYNOPSIS
187
188  use WebService::Simple;
189
190  # Simple use case
191  my $flickr = WebService::Simple->new(
192    base_url => "http://api.flickr.com/services/rest/",
193    param    => { api_key => "your_api_key", }
194  );
195
196  # send GET request to
197  # http://api.flickr.com/service/rest/?api_key=your_api_key&method=flickr.test.echo&name=value
198  $flickr->get( { method => "flickr.test.echo", name => "value" } );
199
200  # send GET request to
201  # http://api.flickr.com/service/rest/extra/path?api_key=your_api_key&method=flickr.test.echo&name=value
202  $flickr->get( "extra/path",
203    { method => "flickr.test.echo", name => "value" });
204
205  # Create a subclass - Encapsulates things better
206  package WebService::Simple::Flickr;
207  use base qw(WebService::Simple);
208  __PACKAGE__->config(
209    base_url => "http://api.flickr.com/services/rest/",
210    upload_url => "http://api.flickr.com/services/upload/",
211  );
212
213  sub test_echo
214  {
215    my $self = shift;
216    $self->get( { method => "flickr.test.echo", name => "value" } );
217  }
218
219  sub upload
220  {
221    my $self = shift;
222    local $self->{base_url} = $self->config->{upload_url};
223    $self->post(
224      Content_Type => "form-data",
225      Content => { title => "title", description => "...", photo => ... },
226    );
227  }
228
229  # Using response objects
230  my $service = WebService::Simple->new(
231    response_parser => MyParser->new
232  );
233  my $resp = $service->get(...);
234  my $blob = $resp->parse_response; # Parsed with MyParser
235
236=head1 DESCRIPTION
237
238WebService::Simple is a simple class to interact with web services.
239
240It's basically an LWP::UserAgent that remembers recurring api URLs and
241parameters, plus sugar to parse the results.
242
243=head1 PARSERS
244
245Web services return their results in various different formats. Or perhaps
246you require more sophisticated results parsing than what WebService::Simple
247provides.
248
249WebService::Simple by default uses XML::Simple, but you can easily override
250that by providing a parser object to the constructor:
251
252  my $service = WebService::Simple->new(
253    response_parser => AVeryComplexParser->new,
254    ...
255  );
256  my $response = $service->get( ... );
257  my $thing = $response->parse_response;
258
259This allows great flexibility in handling different webservices
260
261=head1 AUTHOR
262
263Yusuke Wada  C<< <yusuke@kamawada.com> >>
264
265Daisuke Maki C<< <daisuke@endeworks.jp> >>
266
267=head1 COPYRIGHT AND LICENSE
268
269Copyright (c) 2008 Yusuke Wada, All rights reserved.
270
271This module is free software; you can redistribute it
272and/or modify it under the same terms as Perl itself.
273See L<perlartistic>.
274
275=cut
Note: See TracBrowser for help on using the browser.