Provided by: libponapi-client-perl_0.002012-2_all
NAME
PONAPI::Client - Client to a {JSON:API} service (http://jsonapi.org/) v1.0
VERSION
version 0.002012
SYNOPSIS
use PONAPI::Client; my $client = PONAPI::Client->new( host => $host, port => $port, ); $client->retrieve_all( type => $type ); $client->retrieve( type => $type, id => $id, ); $client->retrieve_relationships( type => $type, id => $id, rel_type => $rel_type, ); $client->retrieve_by_relationship( type => $type, id => $id, rel_type => $rel_type, ); $client->create( type => $type, data => { attributes => { ... }, relationships => { ... }, }, ); $client->delete( type => $type, id => $id, ); $client->update( type => $type, id => $id, data => { type => $type, id => $id, attributes => { ... }, relationships => { ... }, } ); $client->delete_relationships( type => $type, id => $id, rel_type => $rel_type, data => [ { type => $rel_type, id => $rel_id }, ... ], ); $client->create_relationships( type => $type, id => $id, rel_type => $rel_type, data => [ { type => $rel_type, id => $rel_id }, ... ], ); $client->update_relationships( type => $type, id => $id, rel_type => $rel_type, # for a one-to-one: data => { type => $rel_type, id => $rel_id }, # or for a one-to-many: data => [ { type => $rel_type, id => $rel_id }, ... ], ); # If the endpoint uses an uncommon url format: $client->retrieve( type => 'foo', id => 43, # Will generate a request to # host:port/type_foo_id_43 uri_template => "type_{type}_id_{id}", );
DESCRIPTION
"PONAPI::Client" is a {JSON:API} <http://jsonapi.org/> compliant client; it should be able to communicate with any API-compliant service. The client does a handful of checks required by the spec, then uses Hijk to communicate with the service. In most cases, all API methods return a response document: my $response = $client->retrieve(...); In list context however, all api methods will return the request status and the document: my ($status, $response) = $client->retrieve(...) Response documents will look something like these: # Successful retrieve(type => 'articles', id => 2) { jsonapi => { version => "1.0" }, links => { self => "/articles/2" }, data => { ... }, meta => { ... }, # May not be there included => [ ... ], # May not be there, see C<include> } # Successful retrieve_all( type => 'articles' ) { jsonapi => { version => "1.0" }, links => { self => "/articles" }, # May include pagination links data => [ { ... }, { ... }, ... ], meta => { ... }, # May not be there included => [ ... ], # May not be there, see C<include> } # Successful create(type => 'foo', data => { ... }) { jsonapi => { version => "1.0" }, links => { self => "/foo/$created_id" }, data => { type => 'foo', id => $created_id }, } # Successful update(type => 'foo', id => 2, data => { ... }) { jsonapi => { version => "1.0" }, links => { self => "/foo/2" }, # may not be there meta => { ... }, # may not be there } # Error, see http://jsonapi.org/format/#error-objects { jsonapi => { version => "1.0" }, errors => [ { ... }, # error 1 ... # potentially others ], } However, there are situations where the server may respond with a "204 No Content" and no response document; depending on the situation, it might be worth checking the status.
METHODS
new Creates a new "PONAPI::Client" object. Takes a couple of attributes: host The hostname (or IP address) of the service. Defaults to localhost. port Port of the service. Defaults to 5000. send_version_header Sends a "X-PONAPI-Client-Version" header set to the {JSON:API} version the client supports. Defaults to true. retrieve_all retrieve_all( type => $type, %optional_arguments ) Retrieves all resources of the given type. In SQL, this is similar to "SELECT * FROM $type". This handles several arguments: fields Spec <http://jsonapi.org/format/#fetching-sparse-fieldsets>. Instead of returning every attribute and relationship from a given resource, "fields" can be used to specify exactly what is returned. This excepts a hashref of arrayrefs, where the keys are types, and the values are either attribute names, or relationship names. $client->retrieve_all( type => 'people', fields => { people => [ 'name', 'age' ] } ) Note that an attribute not being in fields means the opposite to an attribute having empty fields: # No attributes or relationships for both people and comments $client->retrieve_all( type => 'people', fields => { people => [], comments => [] }, ); # No attributes or relationships for comments, but # ALL attributes and relationships for people $client->retrieve_all( type => 'people', fields => { comments => [] }, ); include Spec <http://jsonapi.org/format/#fetching-includes>. "include" can be used to fetch related resources. The example below is fetching both all the people, and all comments made by those people: my $response = $client->retrieve_all( type => 'people', include => ['comments'] ); "include" expects an arrayref of relationship names. In the response, the resources fetched will be in an arrayref under the top-level "included" key: say $_->{attributes}{body} for @{ $response->{included} } page Spec <http://jsonapi.org/format/#fetching-pagination>. Requests that the server paginate the results. Each endpoint may have different pagination rules. sort Spec <http://jsonapi.org/format/#fetching-sorting>. Requests that the server sort the results in a given way: $client->retrieve_all( type => 'people', sort => [qw/ age /], # sort by age, ascending ); $client->retrieve_all( type => 'people', sort => [qw/ -age /], # sort by age, descending ); Although not all endpoints will support this, it may be possible to sort by a relationship's attribute: $client->retrieve_all( type => 'people', sort => [qw/ -comments.created_date /], ); filter Spec <http://jsonapi.org/format/#fetching-filtering>. This one is entirely dependent on the endpoint. It's usually employed to act as a "WHERE" clause: $client->retrieve_all( type => 'people', filter => { id => [ 1, 2, 3, 4, 6 ], # IN ( 1, 2, ... ) age => 34, # age = 34 }, ); Sadly, more complex filters are currently not available. retrieve retrieve( type => $type, id => $id, %optional_arguments ) Similar to "retrieve_all", but retrieves a single resource. retrieve_relationships retrieve_relationships( type => $type, id => $id, rel_type => $rel_type, %optional_arguments ) Retrieves all of $id's relationships to $rel_type as resource identifiers; that is, as hashrefs that contain only "type" and "id": # retrieve_relationships(type=>'people', id=>2, rel_type=>'comments') { jsonapi => { version => "1.0" }, data => [ { type => 'comments', id => 4 }, { type => 'comments', id => 9 }, { type => 'comments', id => 14 }, ] } These two do roughly the same thing: my $response = $client->retrieve( type => $type, id => $id ); my $relationships = $response->{data}{relationships}{$rel_type}; say join ", ", map $_->{id}, @$relationships; my $response = $client->retrieve_relationships( type => $type, id => $id, rel_type => $rel_type, ); my $relationships = $response->{data}; say join ", ", map $_->{id}, @$relationships; However, "retrieve_relationships" also allows you to page those relationships, which may be quite useful. Keep in mind that "retrieve_relationships" will return an arrayref for one-to-many relationships, and a hashref for one-to-ones. retrieve_by_relationship retrieve_by_relationship( type => $type, id => $id, rel_type => $rel_type, %optional_arguments ) "retrieve_relationships" on steroids. It behaves the same way, but will retrieve full resources, not just resource identifiers; because of this, you can also potentially apply more complex filters and sorts. create create( type => $type, data => { ... }, id => $optional ) Create a resource of type $type using $data to populate it. Data must include the type, and may include two other keys: "attributes" and "relationships": $client->create( type => 'comments', data => { type => 'comments', attributes => { body => 'abc' }, relationships => { author => { type => 'people', id => 55 }, liked_by => [ { type => 'people', id => 55 }, { type => 'people', id => 577 }, ], } } } An optional "id" may be provided, in which case the server may choose to use it when creating the new resource. update update( type => $type, id => $id, data => { ... } ) Can be used to update the resource. Data must have "type" and "id" keys: $client->create( type => 'comments', id => 5, data => { type => 'comments', id => 5, attributes => { body => 'new body!' }, relationships => { author => undef, # no author liked_by => [ { type => 'people', id => 79 }, ], } } } An empty arrayref ("[]") can be used to clear one-to-many relationships, and "undef" to clear one-to-one relationships. A successful "update" will always return a response document; see the spec for more details. Spec <http://jsonapi.org/format/#crud-updating>. delete delete( type => $type, id => $id ) Deletes the resource. update_relationships update_relationships( type => $type, id => $id, rel_type => $rel_type, data => $data ) Update a resource's relationships. Basically a shortcut to using "update". For one-to-one relationships, "data" can be either a single hashref, or undef. For one- to-many relationships, "data" can be an arrayref; an empty arrayref means 'clear the relationship'. create_relationships create_relationships( type => $type, id => $id, rel_type => $rel_type, data => [{ ... }] ) Adds to the specified one-to-many relationship. delete_relationships delete_relationships( type => $type, id => $id, rel_type => $rel_type, data => [{ ... }] ) Deletes from the specified one-to-many relationship.
Endpoint URI format
By default, "PONAPI::Client" assumes urls on the endpoint are in this format: retrieve_all: /$type retrieve: /$type/$id retrieve_by_relationships: /$type/$id/$rel_type retrieve_relationships: /$type/$id/relationships/$rel_type create: /$type or /$type/$id delete: /$type/$id update: /$type/$id update_relationships: /$type/$id/relationships/$rel_type create_relationships: /$type/$id/relationships/$rel_type delete_relationships: /$type/$id/relationships/$rel_type # Will generate a request to /foo/99 $client->retrieve( type => 'foo', id => 99, ); However, if another format is needed, two approaches are possible: URI paths have a common prefix If all the endpoint urls have a common prefix, ala "/v1/articles" instead of simply "/articles", then you can just set "uri_base" as needed: $client->retrieve( type => 'foo', id => 99, uri_base => '/v1' ); We can also set this when creating the client; if done this way, all requests generated from this client will include the base: my $new_client = PONAPI::Client->new( uri_base => '/v1', ... ); # This will generate a request to /v1/foo/99 $new_client->retrieve( type => 'foo', id => 99, ); Completely different uris If the endpoint's expected formats are wildly different, you can specify "uri_template" with your request: # Will generate a request to id_here_99_and_type_there/foo $client->retrieve( type => 'foo', id => 99, uri_template => 'id_here_{id}_and_type_there/{type}' ); These placeholders are recognized: • type • id • rel_type This can only be done on a per-request basis.
AUTHORS
• Mickey Nasriachi <mickey@cpan.org> • Stevan Little <stevan@cpan.org> • Brian Fraser <hugmeir@cpan.org>
COPYRIGHT AND LICENSE
This software is copyright (c) 2019 by Mickey Nasriachi, Stevan Little, Brian Fraser. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.