« Documentation table of contents
- Structure of JSON response
- Return Codes and Code Ranges
- Messages and Localization
- Handling Exceptions API way
- Overriding code to message conversion
- Overriding built-in messages
Predictability, simplicity and no special-case is the key of the ResponseBuilder
and all responses
created by this library guarantee consistent JSON structure by design.
By default response always contain at least the following elements:
{
"success": true,
"code": 0,
"locale": "en",
"message": "OK",
"data": null
}
where
success
(boolean) indicates API method failure or success,code
(int) is your own return code (usually used when returning error message or other failure),locale
(string) represents locale used for returned error message (obtained automatically via\App::getLocale()
). This helps processing the response if you support multiple languages,message
(string) human readable message that is ready to display and explains human readable explanation of thecode
value,data
(object|null) if you return any additional data with your reply, it would end here. If no extra data is needed, that key still be present in the response withnull
value.
NOTE: If you need to return other/different elements in the above structure (not in your
data
), see Manipulating Response Object chapter for detailed information about how
to achieve this.
All return codes are integers however the meaning of the code is fully up to you. The only exception
is 0
(zero) which ALWAYS means success and you cannot use 0
with error()
methods (but
you can have other codes for success than 0
if needed).
In one of my projects we had multiple APIs chained together (so one API called another, remote API).
I wanted to be able to chain API invocations in the way that in case of problems (and cascading
failure) I still would able to tell which one failed first. For example our API client app calls
method of publicly exposed API "A". That API "A" internally calls method of completely different and
separate API "B". Under the hood API "B" delegates some work and talks to API "C". When something go
wrong and "C"'s method fail, client shall see "C"'s error code and error message, not the "A"'s. To
achieve this each API you chain return unique error codes and the values are unique per whole chain
To support that ResponseBuilder
features code ranges, allowing you to configure min_code
and
max_code
you want to be allowed to use in given API. ResponseBuilder
will ensure no values not
from that range is ever returned, so to make the whole chain "clear", you only need to properly
assign non-overlapping ranges to your APIs and ResponseBuilder
do the rest. Any attempt to violate
code range ends up with exception thrown.
First
20
codes in your range (from0
to19
inclusive) are reserved forResponseBuilder
internals and must not be used directly nor assigned to your codes.
Code ranges cannot be turned off, but if you do not need it or you just have one API or need no chaining, then just set
max_code
in your configuration file to some very high value if needed or defaults do not fit.
To keep your source readable and clear, it's strongly recommended to create separate class
ApiCode.php
(i.e. in app/
) and keep all codes there as public const
. This way you protect
yourself from using wrong code or save your time in case you will need to refactor code
range in future. For example, your imaginary app/ApiCode.php
can look like this:
<?php
namespace App;
class ApiCode {
public const SOMETHING_WENT_WRONG = 250;
}
ResponseBuilder
is designed with localization in mind so default approach is you just set it up
once and most things should happen automatically, which also includes creating human readable error
messages. As described in Configuration
section, once you get map
configured, you most likely
will not be in need to manually refer error messages - ResponseBuilder
will do that for you and
you optionally just need to pass array with placeholders' substitution (hence the order of arguments
for errorXXX()
methods). ResponseBuilder
utilised standard Laravel's Lang
class to deal with
messages, so all localization features are supported.
Properly designed REST API should never hit consumer with anything but JSON. While it looks like
easy task, there's always chance for unexpected issue to occur. So we need to expect unexpected and
be prepared when it hit the fan. This means not only things like uncaught exception but also
Laravel's maintenance mode can pollute returned API responses which is unfortunately pretty common
among badly written APIs. Do not be one of them, and take care of that in advance with couple of
easy steps. With Laravel this can be achieved with custom Exception Handler and ResponseBuilder
comes with ready-to-use Handler as well.
See Exception Handling with Response Builder for easy setup information.
ResponseBuilder
automatically provides human readable error messages for each API code used but if
for any reason you want to take control on this, you can now provide own implementation of
RB::getMessageForApiCode()
.
<?php
namespace App;
class MyResponseBuilder extends MarcinOrlowski\ResponseBuilder\ResponseBuilder
{
protected static function getMessageForApiCode(bool $success, int $api_code, array $lang_args = null): string
{
return "My cool message for code {$api_code}";
}
}
Please see current implementation for getMessageForApiCode()
for details how to correctly obtain
localization string key etc.
At the moment ResponseBuilder
provides few built-in messages (
see src/BaseApiCodes.php): one is used for success code 0
and another
provides fallback message for codes without custom mapping. If for any reason you want to override
them, simply map these codes in your map
config using codes from package reserved range:
MarcinOrlowski\ResponseBuilder\BaseApiCodes::OK() => 'my_messages.ok',
and from now on, each success()
will be returning your message instead of built-in one.
To override default error message used when given error code has no entry in map
, add the
following:
MarcinOrlowski\ResponseBuilder\BaseApiCodes::NO_ERROR_MESSAGE() => 'my_messages.default_error_message',
You can use :api_code
placeholder in the message and it will be substituted actual error code
value.