Group
Extension

Museum-Rijksmuseum-Object/lib/Museum/Rijksmuseum/Object.pm

package Museum::Rijksmuseum::Object;

use strictures 2;

use Carp;
use JSON::MaybeXS;
use LWP::UserAgent;
use Moo;
use URI;
use URI::Encode qw( uri_encode );
use URI::QueryParam;

use namespace::clean;

=head1 NAME

Museum::Rijksmuseum::Object - Access the Rijksmuseum object metadata API

=head1 VERSION

Version 0.03

=cut

our $VERSION = '0.03';


=head1 SYNOPSIS

Access the collection, collection details, and collection image endpoints of the Rijksmuseum "Rijksdata" API.

    use Museum::Rijksmuseum::Object;

    my $api           = Museum::Rijksmuseum::Object->new( key => 'abc123xyz', culture => 'en' );
    my $search_result = $api->search( involvedMaker => 'Rembrandt van Rijn' );
    die $search_result->{error} if $search_result->{error};
    print "Results: $search_result->{count}\n";
    for my $item ( $search_result->{artObjects}->@* ) {
        print "Id: $item->{id}\n";
    }

Refer to the L<Rijksmuseum API documentation|https://data.rijksmuseum.nl/object-metadata/api/>
for information on query and response formats. Be aware that the API expects
camelCase on its parameters and this module follows this convention.

=head1 SUBROUTINES/METHODS

=head2 new

    my $api = Museum::Rijksmuseum::Object->new(
        key     => 'abc123xyz',    # the API key supplied by the Rijksmuseum
        culture => 'en',           # the 'culture' parameter, determines the
                                   # language for searching and results
    );

Creates a new object instance. The C<key> and C<culture> parameters are required.

=cut

=head2 search

    my $result = $api->search(
        p       => 3,            # page 3
        ps      => 10,           # 10 results per page
        q       => 'vermeer',    # a general search term
        imgonly => 1,            # image only?
    );

Searches the collection. See the API documentation for parameter details.

=cut

sub search {
    my ( $self, %params ) = @_;

    my $url = $self->_build_url( {}, \%params );
    return $self->_fetch_url($url);
}

=head2 fetch

    my $result = $api->fetch('SK-C-5');

Fetches an individual item from the collection. The parameter is the
C<objectNumber> as returned by the C<search> call.

=cut

sub fetch {
    my ( $self, $object_number ) = @_;

    carp "An object number must be provided to 'fetch'" unless defined $object_number;
    my $url = $self->_build_url( { object_number => $object_number }, {} );
    return $self->_fetch_url($url);
}

=head2 image_info

    my $result = $api->image_info('SK-C-5');

Fetches the information required to build the image tiles for a particular
C<objectNumber>.

=cut

sub image_info {
    my ( $self, $object_number ) = @_;

    carp "An object number must be provided to 'image_info'" unless defined $object_number;
    my $url = $self->_build_url(
        {
            object_number => $object_number,
            tiles         => 1,
        },
        {}
    );
    return $self->_fetch_url($url);
}

sub _build_url {
    my ( $self, $path, $params ) = @_;

    # Determine which URL form we need
    my $url;
    if ( $path->{tiles} ) {
        $url = sprintf(
            'https://www.rijksmuseum.nl/api/%s/collection/%s/tiles',
            uri_encode( $self->culture ),
            uri_encode( $path->{object_number} )
        );
    } elsif ( $path->{object_number} ) {
        $url = sprintf(
            'https://www.rijksmuseum.nl/api/%s/collection/%s',
            uri_encode( $self->culture ),
            uri_encode( $path->{object_number} )
        );
    } else {
        $url =
          sprintf( 'https://www.rijksmuseum.nl/api/%s/collection', uri_encode( $self->culture ) );
    }
    $url = URI->new($url);

    # Add query parameters
    $url->query_param( key => $self->key );
    if ($params) {
        for my $p ( keys %$params ) {
            $url->query_param( $p => $params->{$p} );
        }
    }

    return $url->as_string;
}

sub _fetch_url {
    my ( $self, $url ) = @_;

    my $ua = LWP::UserAgent->new;
    $ua->agent("Museum::Rijksmuseum::Object/$VERSION");

    my $req = HTTP::Request->new( GET => $url );

    my $res = $ua->request($req);
    if ( $res->is_success ) {
        my $json = JSON::MaybeXS->new();
        return $json->decode( $res->content );
    } else {
        return { error => $res->status_line };
    }
}

=head1 ATTRIBUTES

=head2 key

The API key provided by the Rijksmuseum.

=cut

has key => (
    is       => 'rw',
    required => 1,
);

=head2 culture

The 'culture' that the API will return data to you in, and perform searches in.
Typically 'en' or 'nl'.

=cut

has culture => (
    is       => 'rw',
    required => 1
);

=head1 SEE ALSO

For bulk-ingestion of data using the Rijksmuseum OAI-PMH API, see
L<Museum::Rijksmuseum::Object::Harvester>.

=head1 AUTHOR

Robin Sheat, C<< <rsheat at cpan.org> >>

=head1 TODO

=over 4

=item Make a heavier interface

At the moment this is a very thin interface over the Rijksmuseum API. It could
be improved by having helpers to do things, for example optionally
automatically fetching and stitching images.

=back 

=cut

=head1 BUGS

Please report any bugs or feature requests to C<bug-museum-rijksmuseum-object at rt.cpan.org>, or through
the web interface at L<https://rt.cpan.org/NoAuth/ReportBug.html?Queue=Museum-Rijksmuseum-Object>.  I will be notified, and then you'll
automatically be notified of progress on your bug as I make changes.

Alternately, use the tracker on the repository page at L<https://gitlab.com/eythian/museum-rijksmuseum-object>.


=head1 SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc Museum::Rijksmuseum::Object


You can also look for information at:

=over 4

=item * Repository page (report bugs here)

L<https://gitlab.com/eythian/museum-rijksmuseum-object>

=item * RT: CPAN's request tracker (or here)

L<https://rt.cpan.org/NoAuth/Bugs.html?Dist=Museum-Rijksmuseum-Object>

=item * CPAN Ratings

L<https://cpanratings.perl.org/d/Museum-Rijksmuseum-Object>

=item * Search CPAN

L<https://metacpan.org/release/Museum-Rijksmuseum-Object>


=back


=head1 ACKNOWLEDGEMENTS


=head1 LICENSE AND COPYRIGHT

This software is Copyright (c) 2023 by Robin Sheat.

This is free software, licensed under:

  The Artistic License 2.0 (GPL Compatible)


=cut

1; # End of Museum::Rijksmuseum::Object


Powered by Groonga
Maintained by Kenichi Ishigaki <ishigaki@cpan.org>. If you find anything, submit it on GitHub.