File Coverage

blib/lib/Museum/Rijksmuseum/Object.pm
Criterion Covered Total %
statement 27 59 45.7
branch 0 12 0.0
condition n/a
subroutine 9 14 64.2
pod 3 3 100.0
total 39 88 44.3


line stmt bran cond sub pod time code
1             package Museum::Rijksmuseum::Object;
2              
3 1     1   104141 use strictures 2;
  1         1626  
  1         52  
4              
5 1     1   193 use Carp;
  1         3  
  1         53  
6 1     1   504 use JSON::MaybeXS;
  1         8302  
  1         60  
7 1     1   704 use LWP::UserAgent;
  1         51146  
  1         44  
8 1     1   589 use Moo;
  1         6651  
  1         9  
9 1     1   1490 use URI;
  1         3  
  1         29  
10 1     1   490 use URI::Encode qw( uri_encode );
  1         16348  
  1         63  
11 1     1   419 use URI::QueryParam;
  1         96  
  1         30  
12              
13 1     1   469 use namespace::clean;
  1         14771  
  1         8  
14              
15             =head1 NAME
16              
17             Museum::Rijksmuseum::Object - Access the Rijksmuseum object metadata API
18              
19             =head1 VERSION
20              
21             Version 0.01
22              
23             =cut
24              
25             our $VERSION = '0.02';
26              
27              
28             =head1 SYNOPSIS
29              
30             Access the collection, collection details, and collection image endpoints of the Rijksmuseum "Rijksdata" API.
31              
32             use Museum::Rijksmuseum::Object;
33              
34             my $api = Museum::Rijksmuseum::Object->new( key => 'abc123xyz', culture => 'en' );
35             my $search_result = $api->search( involvedMaker => 'Rembrandt van Rijn' );
36             die $search_result->{error} if $search_result->{error};
37             print "Results: $search_result->{count}\n";
38             for my $item ( $search_result->{artObjects}->@* ) {
39             print "Id: $item->{id}\n";
40             }
41              
42             Refer to the L<Rijksmuseum API documentation|https://data.rijksmuseum.nl/object-metadata/api/>
43             for information on query and response formats. Be aware that the API expects
44             camelCase on its parameters and this module follows this convention.
45              
46             =head1 SUBROUTINES/METHODS
47              
48             =head2 new
49              
50             my $api = Museum::Rijksmuseum::Object->new(
51             key => 'abc123xyz', # the API key supplied by the Rijksmuseum
52             culture => 'en', # the 'culture' parameter, determines the
53             # language for searching and results
54             );
55              
56             Creates a new object instance. The C<key> and C<culture> parameters are required.
57              
58             =cut
59              
60             =head2 search
61              
62             my $result = $api->search(
63             p => 3, # page 3
64             ps => 10, # 10 results per page
65             q => 'vermeer', # a general search term
66             imgonly => 1, # image only?
67             );
68              
69             Searches the collection. See the API documentation for parameter details.
70              
71             =cut
72              
73             sub search {
74 0     0 1   my ( $self, %params ) = @_;
75              
76 0           my $url = $self->_build_url( {}, \%params );
77 0           return $self->_fetch_url($url);
78             }
79              
80             =head2 fetch
81              
82             my $result = $api->fetch('SK-C-5');
83              
84             Fetches an individual item from the collection. The parameter is the
85             C<objectNumber> as returned by the C<search> call.
86              
87             =cut
88              
89             sub fetch {
90 0     0 1   my ( $self, $object_number ) = @_;
91              
92 0 0         carp "An object number must be provided to 'fetch'" unless defined $object_number;
93 0           my $url = $self->_build_url( { object_number => $object_number }, {} );
94 0           return $self->_fetch_url($url);
95             }
96              
97             =head2 image_info
98              
99             my $result = $api->image_info('SK-C-5');
100              
101             Fetches the information required to build the image tiles for a particular
102             C<objectNumber>.
103              
104             =cut
105              
106             sub image_info {
107 0     0 1   my ( $self, $object_number ) = @_;
108              
109 0 0         carp "An object number must be provided to 'image_info'" unless defined $object_number;
110 0           my $url = $self->_build_url(
111             {
112             object_number => $object_number,
113             tiles => 1,
114             },
115             {}
116             );
117 0           return $self->_fetch_url($url);
118             }
119              
120             sub _build_url {
121 0     0     my ( $self, $path, $params ) = @_;
122              
123             # Determine which URL form we need
124 0           my $url;
125 0 0         if ( $path->{tiles} ) {
    0          
126             $url = sprintf(
127             'https://www.rijksmuseum.nl/api/%s/collection/%s/tiles',
128             uri_encode( $self->culture ),
129             uri_encode( $path->{object_number} )
130 0           );
131             } elsif ( $path->{object_number} ) {
132             $url = sprintf(
133             'https://www.rijksmuseum.nl/api/%s/collection/%s',
134             uri_encode( $self->culture ),
135             uri_encode( $path->{object_number} )
136 0           );
137             } else {
138 0           $url =
139             sprintf( 'https://www.rijksmuseum.nl/api/%s/collection', uri_encode( $self->culture ) );
140             }
141 0           $url = URI->new($url);
142              
143             # Add query parameters
144 0           $url->query_param( key => $self->key );
145 0 0         if ($params) {
146 0           for my $p ( keys %$params ) {
147 0           $url->query_param( $p => $params->{$p} );
148             }
149             }
150              
151 0           return $url->as_string;
152             }
153              
154             sub _fetch_url {
155 0     0     my ( $self, $url ) = @_;
156              
157 0           my $ua = LWP::UserAgent->new;
158 0           $ua->agent("Museum::Rijksmuseum::Object/$VERSION");
159              
160 0           my $req = HTTP::Request->new( GET => $url );
161              
162 0           my $res = $ua->request($req);
163              
164 0 0         if ( $res->is_success ) {
165 0           my $json = JSON::MaybeXS->new( utf8 => 1 );
166 0           return $json->decode( $res->content );
167             } else {
168 0           return { error => $res->status_line };
169             }
170             }
171              
172             =head1 ATTRIBUTES
173              
174             =head2 key
175              
176             The API key provided by the Rijksmuseum.
177              
178             =cut
179              
180             has key => (
181             is => 'rw',
182             required => 1,
183             );
184              
185             =head2 culture
186              
187             The 'culture' that the API will return data to you in, and perform searches in.
188             Typically 'en' or 'nl'.
189              
190             =cut
191              
192             has culture => (
193             is => 'rw',
194             required => 1
195             );
196              
197             =head1 SEE ALSO
198              
199             For bulk-ingestion of data using the Rijksmuseum OAI-PMH API, see
200             L<Museum::Rijksmuseum::Object::Harvester>.
201              
202             =head1 AUTHOR
203              
204             Robin Sheat, C<< <rsheat at cpan.org> >>
205              
206             =head1 TODO
207              
208             =over 4
209              
210             =item Make a heavier interface
211              
212             At the moment this is a very thin interface over the Rijksmuseum API. It could
213             be improved by having helpers to do things, for example optionally
214             automatically fetching and stitching images.
215              
216             =back
217              
218             =cut
219              
220             =head1 BUGS
221              
222             Please report any bugs or feature requests to C<bug-museum-rijksmuseum-object at rt.cpan.org>, or through
223             the web interface at L<https://rt.cpan.org/NoAuth/ReportBug.html?Queue=Museum-Rijksmuseum-Object>. I will be notified, and then you'll
224             automatically be notified of progress on your bug as I make changes.
225              
226             Alternately, use the tracker on the repository page at L<https://gitlab.com/eythian/museum-rijksmuseum-object>.
227              
228              
229             =head1 SUPPORT
230              
231             You can find documentation for this module with the perldoc command.
232              
233             perldoc Museum::Rijksmuseum::Object
234              
235              
236             You can also look for information at:
237              
238             =over 4
239              
240             =item * Repository page (report bugs here)
241              
242             L<https://gitlab.com/eythian/museum-rijksmuseum-object>
243              
244             =item * RT: CPAN's request tracker (or here)
245              
246             L<https://rt.cpan.org/NoAuth/Bugs.html?Dist=Museum-Rijksmuseum-Object>
247              
248             =item * CPAN Ratings
249              
250             L<https://cpanratings.perl.org/d/Museum-Rijksmuseum-Object>
251              
252             =item * Search CPAN
253              
254             L<https://metacpan.org/release/Museum-Rijksmuseum-Object>
255              
256              
257             =back
258              
259              
260             =head1 ACKNOWLEDGEMENTS
261              
262              
263             =head1 LICENSE AND COPYRIGHT
264              
265             This software is Copyright (c) 2023 by Robin Sheat.
266              
267             This is free software, licensed under:
268              
269             The Artistic License 2.0 (GPL Compatible)
270              
271              
272             =cut
273              
274             1; # End of Museum::Rijksmuseum::Object