pericmd 013: Enveloped result

If you see the hello script from the previous post, you’ll see one peculiar thing:

$SPEC{hello} = {
    v => 1.1,
    summary => 'Say hello',
};
sub hello {
    [200, "OK", "Hello, world!"];
}

Why does hello() return an array [200,”OK”,”Hello, world!”] instead of just a string “Hello, world!”. I’m calling this enveloped result, and this is specified in Rinci::function. Basically, enveloped result allows returning status of operation (whether the operation succeeds or fails, and its error code) as well as result of operation. Traditionally in C and Perl, error code is returned in another, global variable errno/$!/$? (with all the trappings of being a global variable). With enveloped result, both error code and result are returned together.

This has a nice property of mapping very nicely to HTTP response, especially since I also steal a lot of HTTP status codes to mean exactly like they are in HTTP, for example: 200 is success, 404 is not found, 500 is general error, 501 is not implemented, and so on. The first element of the enveloped result array is the status code, just like HTTP status code (most of the time). The second element is the error message, just like HTTP status message. The third element contains the actual payload. And there can be a fourth element which is a hash, analogous to HTTP response headers (examples will be given later).

In a CLI program, normally when the result is a success and shown using the format “text” (which is the default format), we don’t show the status code and message. We just show the actual result a.k.a. the payload:

% ./hello
Hello, world!

But if we use other formats, for example json, this enveloped result can be displayed in full:

% ./hello --format json
[200,"OK","Hello, world!",{}]

As you can also see, Perinci::CmdLine does some checking and normalization of the enveloped result (fourth element set to empty hash).

Let’s see what happens if we return a non-success result in the function:

$SPEC{hello} = {
    v => 1.1,
    summary => 'Say hello',
};
sub hello {
    [404, "Sorry, world not found"];
}
% ./hello
ERROR 404: Sorry, world not found

% ./hello format json
[404,"Sorry, world not found",null,{}]

When we return an error response, we usually don’t bother to set an actual result (third element of enveloped result): we only set status code and error message.

Now let’s see the exit code:

% echo $?
104

As a convenient convention, exit code of CLI program is set as (status message – 300). So if status is 404, exit code is 104. But, for success statuses (2xx) exit code will be 0.

What if I don’t want to return enveloped results? You might already have an existing function that you don’t want to or can’t modify. Or the function is simple and returns simple values, and/or “never fails”, or just die on failure. In these cases, it’s admittedly an overkill to have to return an enveloped result.

You can return “naked” values by setting this metadata property:

$SPEC{hello} = {
    v => 1.1,
    summary => 'Say hello',
    result_naked => 1,
};
sub hello {
    "Hello, world!";
}

This way, Perinci::CmdLine knows that your function returns naked values without envelopes, and will adjust accordingly.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s