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

Revision 9694, 6.6 kB (checked in by daisuke, 5 years ago)

lang/perl/WebService-Simple; Add caching

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