=pod

=for vim
   vim: tw=72 ts=3 sts=3 sw=3 et ai :

=encoding utf8

=head1 NAME

WebService::MyJSONs - Perl SDK to consume the MyJSONs web service


=head1 VERSION

This document describes WebService::MyJSONs version 0.002.

=begin html

<a href="https://travis-ci.org/polettix/WebService-MyJSONs">
<img alt="Build Status" src="https://travis-ci.org/polettix/WebService-MyJSONs.svg?branch=master">
</a>
<a href="https://www.perl.org/">
<img alt="Perl Version" src="https://img.shields.io/badge/perl-5.24+-brightgreen.svg">
</a>
<a href="https://badge.fury.io/pl/WebService-MyJSONs">
<img alt="Current CPAN version" src="https://badge.fury.io/pl/WebService-MyJSONs.svg">
</a>
<a href="http://cpants.cpanauthors.org/dist/WebService-MyJSONs">
<img alt="Kwalitee" src="http://cpants.cpanauthors.org/dist/WebService-MyJSONs.png">
</a>
<a href="http://www.cpantesters.org/distro/O/WebService-MyJSONs.html?distmat=1">
<img alt="CPAN Testers" src="https://img.shields.io/badge/cpan-testers-blue.svg">
</a>
<a href="http://matrix.cpantesters.org/?dist=WebService-MyJSONs">
<img alt="CPAN Testers Matrix" src="https://img.shields.io/badge/matrix-@testers-blue.svg">
</a>

=end html

=head1 SYNOPSIS

Functional interface:

   use WebService::MyJSONs qw< myjsons_put myjsons_get >;

   # create a new item, get item's code back
   my $code = myjsons_put({ foo => 'bar' });

   # retrieve data for $code
   my $retrieved_data = myjsons_get($code);

   # update data for $code
   myjsons_put($code, { foo => 'bar', baz => 42 });

Function C<myjsons_put> doubles down on creation of a new slot or update
of the slot, depending on the number of parameters (one or two,
respectively). The interface above takes care to convert it to/from JSON
as needed.

JSON-specific API:

   use WebService::MyJSONs qw< myjsons_put_json myjsons_get_json >;

   my $code = myjsons_put_json('{"foo":"bar"}');
   my $json = myjsons_get_json($code);
   myjsons_put_json($code, '{"foo":"bar", "baz": "yay!"}');

Again, C<myjsons_put_json> doubles down on creation and update.

Object-oriented interface (remote JSON item code is cached when
available):

   use WebService::MyJSONs;

   my $mj1 = WebService::MyJSONs->new;

   # initialize with a $code
   $code = '5ef6366';
   my $mj2 = WebService::MyJSONs->new(code => $code);

   # set endpoint explicitly (e.g. a different one)
   my $url = 'https://www.myjsons.com';
   my $mj3 = WebService::MyJSONs->new(endpoint => $url);

Objects that do not have a cached code inside will invoke the creation
of a new remote item and then cache the code returned by the web
service.

In the next example, C<$mj> starts without a code inside, so the first
put takes care to create a new remote item and cache its code inside the
object, while the second put is an update to that remote item.

   my $mj = WebService::MyJSONs->new;
   $mj->put({ foo => 'bar', hex => [ 0 .. 9, 'a' .. 'f' ] });
   say $mj->code;
   my $retrieved_data = $mj->get;
   $mj->put({ foo => 'bar', hex => [ 0 .. 9, 'A' .. 'F' ] });

There’s of course the counterpart when playing directly with JSON
strings:

   my $mj = WebService::MyJSONs->new;
   $mj->put_json('{"foo":"bar"}');
   my $json = $mj->get_json;
   $mj->put_json('{"foo":"barbaz"}');

Using a different remote JSON item code (does not update the cached
one):

   my $mj = WebService::MyJSONs->new($somecode);
   my $data = $mj->get($code);
   my $json = $mj->get($json);
   $mj->put($code, $data);
   $mj->put_json($code, $json);

C<put>/C<put_json> can also act as constructors when called as class
methods:

   my $mj_a = WebService::MyJSONs->put($data);
   my $mj_b = WebService::MyJSONs->put($code, $data);
   my $mj_c = WebService::MyJSONs->put_json($json);
   my $mj_d = WebService::MyJSONs->put_json($code, $json);

C<get>/C<get_json> can be called as class methods as well:

   my $data = WebService::MyJSONs->get($code);
   my $json = WebService::MyJSONs->get_json($code);


=head1 DESCRIPTION

L<https://www.myjsons.com> is a handy service that can host some JSON
data for us, e.g. for test/mock purposes.

As long as it keeps its interface as of the end of October 2022, this
module can help interacting with the web service.

See the L</SYNOPSIS> for an overview of the different ways of using it.

=head1 INTERFACE

There are a I<functional> and an I<object-oriented> interfaces provided
by the module. It can also act as a I<modulino>.

=head2 Modulino

The module can be invoked as a Perl program, like this:

   # print a help message
   perl /path/to/MyJSONs.pm

   # create a new remote item, new code is printed on STDOUT
   code=$(perl /path/to/MyJSONs.pm put </path/to/stuff.json)

   # update a remote item
   perl /path/to/MyJSONs.pm put $somecode </path/to/stuff.json

   # retrieve JSON stuff, printed on STDOUT
   perl /path/to/MyJSONs.pm get $somecode | jq .

The actual implementation is provided by L</myjsons_cmdline>.

As there is no dependency that is not in CORE, it's possible to copy the
Perl module file somewhere in C<PATH> (e.g. with file name C<myjsons>)
and invoke it as a program.

=head2 Functional Interface

All of the functions below can be imported at once using import string
C<:all>, like this:

   use WebService::MyJSONs ':all';

=head3 B<< myjsons_cmdline >>

   myjsons_cmdline();               # 1
   myjsons_cmdline('help');         # 2
   myjsons_cmdline('get', $code);   # 3
   myjsons_cmdline('put');          # 4
   myjsons_cmdline('put', $code);   # 5

Implement a simple program to use the functionalities from the command
line, like this:

   use WebService::MyJSONs 'myjsons_cmdline';
   myjsons_cmdline(@ARGV);

All JSON input/output is performed through STDIN/STDOUT respectively.

Calls C<1> and C<2> print a help message and exit with status code C<1>.

Call C<3> retrieves the JSON string at C<$code> and prints it on STDOUT.

Calls C<4> and C<5> read the JSON string from STDIN and send it to the
remote server. C<4> creates a new item, C<5> updates the object at
C<$code>. Both print out the item's code.

=head3 B<< myjsons_get >>

   my $data = myjsons_get($code);

Get data from the web service, pointed by C<$code>. The JSON object
retrieved is turned into a Perl data structure by means of L<JSON::PP>.

=head3 B<< myjsons_get_json >>

   my $data = myjsons_get_json($code);

Get a JSON string from the web service, pointed by C<$code>.

=head3 B<< myjsons_put >>

   my $code = myjsons_put($data);
   myjsons_put($code, $data);

Put some data in the web service. C<$data> is turned into a JSON string
by means of L<JSON::PP>.

The first call only provides C<$data> and triggers the addition of a new
item in the web service, returning the code of the newly created item.

The second call example provides both C<$code> and C<$data>, leading to
an update operation (unless C<$code> is C<undef>). It also returns the
code.

=head3 B<< myjsons_put_json >>

   my $code = myjsons_put_json($json);
   myjsons_put_json($code, $json);

Put a JSON string in the web service.

The first call only provides C<$json> and triggers the addition of a new
item in the web service, returning the code of the newly created item.

The second call example provides both C<$code> and C<$json>, leading to
an update operation (unless C<$code> is C<undef>). It also returns the
code.

=head2 Object-oriented Interface

The object-oriented interface provides a finer granularity control.

=head2 B<< code >>

   my $code = $mj->code;
   $mj->code($new_code);

Accessor for the I<code>, i.e. the unique identifier of the JSON string
in the web service.

=head2 B<< get >>

   my $data = $mj->get;                # instance method, cached code
   $data = $mj->get($code);            # instance method, explicit code
   $data = WebService::MyJSONs->get($code); # class method

Retrieve data, taking care to transform the retrieved JSON string into a
Perl data structure with L<JSON::PP>.

The instance call with the C<$code> uses the provided value, leaving the
cached code (if any) unchanged.

=head2 B<< get_json >>

   my $json = $mj->get_json;            # instance method, cached code
   $json = $mj->get_json($code);        # instance method, explicit code
   $json = WebService::MyJSONs->get_json($code); # class method

Retrieve a JSON string.

The instance call with the C<$code> uses the provided value, leaving the
cached code (if any) unchanged.

=head2 B<< new >>

   my $mj = WebService::MyJSONs->new(%args);

Constructor. Allowed keys are:

=over

=item C<code>

a unique code for a remote JSON item. See also L</code>.

=item C<endpoint>

the endpoint to use instead of the default one. See also L</Package
Variables>.

=item C<response_callback>

A callback function with the following signature:

   sub ($response) { ... }

After each call to L<HTTP::Tiny>, a C<$response> object is retrieved and
then passed to this callback function. It can be e.g. useful for
troubleshooting purposes.

=back

=head2 B<< put >>

   $mj->put($data);                                   # 1
   $mj->put($code, $data);                            # 2
   my $obj = WebService::MyJSONs->put($data);         # 3
   my $obj = WebService::MyJSONs->put($code, $data);  # 4

Transform C<$data> into a JSON string with L<JSON::PP> and store it
remotely.

Alternative C<1> generates a new item in the web service, unless a
L</code> is cached (either because of a previous invocation, or because
passed explicitly upon construction). If the code is available, it acts
as an updater.

Alternative C<2> updates the remote item corresponding to C<$code> if
this is defined. If C<$code> is C<undef>, it acts just like C<1>.

Alternative C<3> acts as a constructor that also creates a remote item
and sets the object's L</code> accordingly.

Alternative C<4> with a defined C<$code> acts as a constructor with the
C<$code> and then updates the corresponding remote object. If C<$code>
is C<undef>, it acts just like C<3>.

=head2 B<< put_json >>

   $mj->put_json($json);                                   # 1
   $mj->put_json($code, $json);                            # 2
   my $obj = WebService::MyJSONs->put_json($json);         # 3
   my $obj = WebService::MyJSONs->put_json($code, $json);  # 4

See L</put>, the only difference is that JSON strings are used instead
of data structures, so no automatic encoding happens.

=head2 Package Variables

The package variable C<$DEFAULT_ENDPOINT> can be manipulated to point
the module to a different web service instance, providing the same API.
Its value is used by the functions in the L</Functional Interface>, as
well as the default C<endpoint> value in the L</Object-oriented
Interface>.


=head1 BUGS AND LIMITATIONS

Minimum perl version 5.24.

Report bugs through GitHub (patches welcome) at
L<https://github.com/polettix/WebService-MyJSONs>.

=head1 AUTHOR

Flavio Poletti <flavio@polettix.it>

=head1 COPYRIGHT AND LICENSE

Copyright 2022 by Flavio Poletti <flavio@polettix.it>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.


=cut
