Announcing API Problem 3.x for PHP, complete with PSR-17 support

in #phplast year

(I'm sure that's a bunch of gibberish for the non-developers in the room, but it matters to the PHP developers, I swear...)

After a longer than intended delay, I'm happy to announce the 3.0 release of my Crell/ApiProblem library.

ApiProblem is a small, self-contained library for modeling IETF RFC 7807 "Problem Details" messages. (I know, more gibberish.) That is, it makes it easier for PHP developers to build a message for their API servers to handle cases where Something Bad Happened(tm).

The what with the what?

From the project page:

RFC 7807 is a simple specification for formatting error responses from RESTful APIs on the web. This library provides a simple and convenient way to interact with that specification. It supports generating and parsing RFC 7807 messages, in both JSON and XML variants.

That lets you do things like this:

use Crell\ApiProblem\ApiProblem;

$problem = new ApiProblem("You do not have enough credit.", "");
  ->setDetail("Your current balance is 30, but that costs 50.")
$problem['balance'] = 30;
$problem['accounts'] = [

$json_string = $problem->asJson();

I've tagged a 2.1 release, which will be the last release that supports PHP 5. That line is now ended.

The new hotness

The new 3.0 release targets PHP 7.1 and later, and is fully typed. It also now includes a converter object that will turn an ApiProblem object into a PSR-7 Response object, courtesy of the recently (this year) passed PSR-17 HTTP Factory standard.

That is, if you're working with ApiProblem in a framework that uses PSR-7 Request/Response objects, you can easily create a Response object like so:

$factory = getResponseFactoryFromSomewhere();

// The second paramter says whether to pretty-print the output.
$converter = new HttpConverter($factory, true);

$response = $converter->toJsonResponse($problem);

And now you have a $response you can ship back to the client.


I considered changing the API to have an immutable object, much as other value-object systems have been doing in the wake of PSR-7. However, I attempted to do so and quickly ran into a usability problem. The IETF spec allows for arbitrarily nested extra properties. With the current API, that can be easily handled like so:

$problem = new ApiProblem('Title', '');
$problem['sir'] = 'Gir';
$problem['irken']['invader'] = 'Zim';

If the ArrayAccess interface is replaced with a formal method and an immutable object, the simple property set becomes:

$problem = $problem->withExtension('sir', 'Gir');

Which is doable. But the complex case becomes... I'm not sure what. Probably something I'd have to string parse in some way, which means, uh, no. If someone can help me figure out a convenient, flexible, non-painful syntax for that sort of case I may consider it for a future 4.x version, but for now this will do.

Do I need this thing?

It depends what you're doing. If you're writing a typical website, then, no, probably not. If you're building a RESTful API server in PHP and want to handle error messages in a standard, easily parsable, convenient way, then most definitely.

Happy API serving!