A possible SYNOPSIS for a MyJSONs module

TL;DR

Jotting down how to interact with an hypothetical module for MyJSONs.

In post Software Tools for Hobby-Scale Projects I played a bit with the web service MyJSONs and it seems to work. At least, as of today.

More often than not these service appear and disappear. This specific one was probably born out of MyJSON (without the final s), which is no more. Anyway, we can have some fun in the meantime, right?

So I started playing with the idea of a module. How would I like to use it? Let’s see…

First, it would be handy to have a functional interface, like this:

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 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 treats $data as… data, so it takes care to convert it to/from JSON as needed.

This brings us to the next need: using JSON directly. This is where a JSON-specific API can come handy:

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, the “put” method myjsons_put_json doubles down on creation and update.

Now, of course, we might be interested into an object-oriented interface. Did I hear over-engineering?!?

The basic API works on the assumption that an object will keep the code of the remote JSON fragment as soon as it can, possibly upon invoking the new constructor.

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);

The plain API has get/get_json/put/put_json just like the functional counterpart. 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, $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"}');

Now things start becoming a little more over-engineered at this point.

The first bit is that the code inside an object is just the default. Both the get* and the put* functions also accept another (initial) parameter with a different code, which will be used instead for the specific call (i.e. the cached code will not be changed):

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);

Well, there are a few nitty-gritty details, e.g. if we use undef onto an object without a cached code, it will indeed be initialized. Whatever.

The second piece of over-engineering is that the put/put_json pair can double-down to also instantiate an object, as they always return the instance. Hence, it’s possible to call them as class methods instead, and get an initialized object back. Depending on the presence of the code or not, this will be a remote creation or an update:

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);

At this point, it would just be unjust if the corresponding get/get_json would only be instance methods. So… this works too:

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

So I guess that this is the SYNOPSIS of the module!


Comments? Octodon, , GitHub, Reddit, or drop me a line!