A simple implementation of the api-problem specification. Includes PSR-15 support.

Overview

ApiProblem

Build Status

This library provides a simple and straightforward implementation of the IETF Problem Details for HTTP APIs, RFC 7807.

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.

Generating responses

What's that you say? Someone sent your API a bad request? Tell them it's a problem!

use Crell\ApiProblem\ApiProblem;

$problem = new ApiProblem("You do not have enough credit.", "http://example.com/probs/out-of-credit");
// Defined properties in the API have their own setter methods.
$problem
  ->setDetail("Your current balance is 30, but that costs 50.")
  ->setInstance("http://example.net/account/12345/msgs/abc");
// But you can also support any arbitrary extended properties!
$problem['balance'] = 30;
$problem['accounts'] = [
  "http://example.net/account/12345",
  "http://example.net/account/67890"
];

$json_string = $problem->asJson();

// Now send that JSON string as a response along with the appropriate HTTP error
// code and content type which is available via ApiProblem::CONTENT_TYPE_JSON.
// Also check out asXml() and ApiProblem::CONTENT_TYPE_XML for the angle-bracket fans in the room.

Or, even better, you can subclass ApiProblem for a specific problem type (since the type and title are supposed to go together and be relatively fixed), then just populate your own error-specific data. Just like extending an exception!

If you're using a library or framework that wants to do its own JSON serialization, that's also fully supported. ApiProblem implements\JsonSerializable, so you can pass it directly to json_encode() as if it were a naked array.

$response = new MyFrameworksJsonResponse($problem);

// Or do it yourself
$body = json_encode($problem);

Sending Responses

You're probably using PSR-7 for your responses. That's why this library includes a utility to convert your ApiProblem object to a PSR-7 ResponseInterface object, using a PSR-17 factory of your choice. Like so:

use Crell\ApiProblem\HttpConverter;

$factory = getResponseFactoryFromSomewhere();

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

$response = $converter->toJsonResponse($problem);
// or
$response = $converter->toXmlResponse($problem);

That gives back a fully-functional and marked Response object, ready to send back to the client.

Receiving responses

Are you sending messages to an API that is responding with API-Problem errors? No problem! You can easily handle that response like so:

use Crell\ApiProblem\ApiProblem;

$problem = ApiProblem::fromJson($some_json_string);
$title = $problem->getTitle();
$type = $problem->getType();
// Great, now we know what went wrong, so we can figure out what to do about it.

(It works for fromXml(), too!)

Installation

Install ApiProblem like any other Composer package:

composer require crell/api-problem

See the Composer documentation for more details.

License

This library is released under the MIT license. In short, "leave the copyright statement intact, otherwise have fun." See LICENSE for more information.

Contributing

Pull requests accepted! The goal is complete conformance with the IETF spec.

Comments
  • Removing empty usage on decoding

    Removing empty usage on decoding

    As a follow up to #33 I'm also removing empty usage on decompiling the Problem object to remove the following bug

    <?php
    
    echo ApiProblem::fromJson('{"type":"0"}')->asJson();
    // expected {"type":"0"} but got {"type":"about:blank"} instead
    
    opened by nyamsprod 7
  • Static function to create fromArray()

    Static function to create fromArray()

    The acme protocol returns in https://tools.ietf.org/html/draft-ietf-acme-acme-17#section-7.1.3 an error object which is in the format of RFC 7807. To get this informations into a ApiProblem we need to perform a json_decode of the payload. Extract 'error' and json_encode the data to be passed to ApiProblem::fromJson.

    It would be easier to just have a static function like decompile named ApiProblem::fromArray() to perform the work.

    opened by dol 6
  • Feature/add problem interface

    Feature/add problem interface

    @Crell This PR tentatively tries to introduce an Interface for the ApiProblem package.

    I say tentatively because I wonder if this should be done using something la PHP-FIG or if this is useful to enable swapping or using other package using object following RFC7807 like https://github.com/phpro/api-problem .

    Also I tried to extract the interface without introducing any BC break

    If you find this useful the remaining/open question are:

    Naming issues:

    • should the interface be simply called Problem vs ApiProblemInterface
    • should we used Problem::toArray vs Problem::asArray

    New methods/classes

    • the set/getExtensions methods are added to enable access to the extension members easily
    • should we introduce a specific Exception if a setter method fails ?

    Out of scope features

    • Currently the Problem interface does not support the JsonSerializable or the ArrayAccess interface as such any conversion feature like asXml or asJson are not present in the interface and are specific to the current implementation.
    • In contrary asArray is kept in the interface as the other representations can be infer from it. As a consequence, HttpConverter is rewritten internally to only work with the asArray method.
    • Using PHP native JsonException as this requires at least a PHP requirement bump and maybe a full BC break.

    let me know what you think

    opened by nyamsprod 5
  • Error with type hint

    Error with type hint

    Crell\ApiProblem\ApiProblem sets $title (and $type) property only if argument isn't empty, but getters requires a string return value.

    I think is possible to remove conditions in constructor. If you enable strict types, currently it would throw an error.

    Same thing for other properties, they are null by default, but getters' return values aren't nullable.

    opened by thomasvargiu 5
  • fromJson method doesn't throw an appropriate exception for invalid JSON

    fromJson method doesn't throw an appropriate exception for invalid JSON

    When invalid JSON is passed to ApiProblem::fromJson(), I get a PHP notice and an exception:

    • Argument 1 passed to Crell\ApiProblem\ApiProblem::decompile() must be an array, null given
    • The provided problem string is invalid. The "title" property is required.

    I think it would be appropriate to throw an exception about the invalid JSON, rather than one about the missing title.

    opened by becw 5
  • Any reason why json_encode() is not supported?

    Any reason why json_encode() is not supported?

    Syntactic sugar I know, but there are many instances where objects are put through jason_encode() to serialise them. Once example is Laravel or Lumen, where you can return an object and it will be encoded as a JSON payload, for example:

    return response()->json($problem);
    

    It would be great if that were simply handled without converting to JSON first. The above example returns the payload as [] instead of an RFC7807 object.

    These work for Laravel at present as the return from a controller:

    return response($problem->asJson(), $statusCode, ['Content-Type' => 'application/problem+json']);
    
    return response()->json($problem->asArray(), $statusCode);
    

    I will look at the PSR-7 generation too, as that makes sense for other frameworks and simple apps.

    Is this something that you prefer not to support, or just something nobody has got around to?

    opened by judgej 4
  • Issue #26 support rendering using json_encode()

    Issue #26 support rendering using json_encode()

    Simple JsonSerializable support.

    This is useful in frameworks such as Laravel or Lumen that will accept any object as a HTTP response payload that can be JSON serialised.

    Resolves #26

    opened by judgej 3
  • PSR-7 converter

    PSR-7 converter

    This adds a converter utility to convert a Problem object directly to a PSR-7 Response object.

    At the moment it depends on Zend Diactoros for the Stream object support.

    in progress 
    opened by Crell 3
  • Add an

    Add an "asArray()" method to get the compiled data as a native PHP array

    Awesome project.

    It would be great to add an ApiProblem::asArray() method to get the compiled data as a native PHP array. The use case I have is to more easily integrate this project into a Silex app, where JSON data is returned by adding the following statement to your callback:

    $app->error(function (\Exception $e, $code) use ($app) {
      // ...
      return $app->json($data);
    });
    

    Without a method to get a native PHP array, I have to re-implement some header-setting in the json() method in order for things to be treated the same way as JSON in the rest of the application.

    Thanks in advance for any attention you can give to this, Chris

    opened by cpliakas 3
  • PHP 8.1 compatibility issues

    PHP 8.1 compatibility issues

    When upgrading an app to PHP 8.1, while using version 3.5.1, we see the following issues:

    Deprecated: Return type of Crell\ApiProblem\ApiProblem::offsetExists($offset) should either be compatible with ArrayAccess::offsetExists(mixed $offset): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in [directory]/vendor/crell/api-problem/src/ApiProblem.php on line 599
    
    Deprecated: Return type of & Crell\ApiProblem\ApiProblem::offsetGet($offset) should either be compatible with ArrayAccess::offsetGet(mixed $offset): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in [directory]/vendor/crell/api-problem/src/ApiProblem.php on line 607
    
    Deprecated: Return type of Crell\ApiProblem\ApiProblem::offsetSet($offset, $value) should either be compatible with ArrayAccess::offsetSet(mixed $offset, mixed $value): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in [directory]/vendor/crell/api-problem/src/ApiProblem.php on line 615
    
    Deprecated: Return type of Crell\ApiProblem\ApiProblem::offsetUnset($offset) should either be compatible with ArrayAccess::offsetUnset(mixed $offset): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in [directory]vendor/crell/api-problem/src/ApiProblem.php on line 623
    
    Deprecated: Return type of Crell\ApiProblem\ApiProblem::jsonSerialize() should either be compatible with JsonSerializable::jsonSerialize(): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in [directory]/vendor/crell/api-problem/src/ApiProblem.php on line 520
    

    Since some of the signatures will now include the mixed argument & return type (like offsetGet($offset) -> offsetGet(mixed $offset): mixed), this will mean dropping PHP 7.*

    Maybe a new major version could be created to accommodate this?

    opened by bramslob 1
  • Adding PHP8 test and switching to github actions

    Adding PHP8 test and switching to github actions

    • This PR add more PHP versions tests to ApiProblem (testing against PHP>=7.1 and PHP8)
    • Switch from Travis/Scrutinizer to Github actions
    • Switch from Zend-Diactoros to Laminas-Diactoros
    opened by nyamsprod 1
Owner
Larry Garfield
Staff Engineer for @TYPO3. PHP fan. Functional programming enthusiast. Anything worth doing is worth doing well.
Larry Garfield
This is an implementation of PSR specification. It allows you to send and consume message with Redis store as a broker.

This is an implementation of PSR specification. It allows you to send and consume message with Redis store as a broker.

Enqueue 35 Nov 4, 2022
A small, modern, PSR-7 compatible PSR-17 and PSR-18 network library for PHP, inspired by Go's net package.

Net A small, modern, PSR-7 compatible PSR-17 and PSR-18 network library for PHP, inspired by Go's net package. Features: No hard dependencies; Favours

Minibase 16 Jun 7, 2022
A small, modern, PSR-7 compatible PSR-17 and PSR-18 network library for PHP, inspired by Go's net package.

Net A small, modern, PSR-7 compatible PSR-17 and PSR-18 network library for PHP, inspired by Go's net package. Features: No hard dependencies; Favours

Minibase 16 Jun 7, 2022
Do you want CronJob to follow the solar date?You need this package to solve this problem.

Shamsic Maybe it happened to you that you wanted to use CronJob in your project and you realized that you cannot manage the exact dates that are in th

Amin Ghaninia 5 Jul 19, 2022
⭕️ A Knight's Tour problem solver written in php

Knight's tour problem solver A knight's tour problem solver using "Warnsdorff's Rule" - https://vrgl.ir/IB9LJ ?? About the Project ?? Screenshots ?? B

Mahdiyar Ghannad 8 Nov 6, 2022
This package implements 0-1 Knapsack Problem algorithm i.e. allows to find the best way to fill a knapsack of a specified volume with items of a certain volume and value.

This package implements "0-1 Knapsack Problem" algorithm i.e. allows to find the best way to fill a knapsack of a specified volume with items of a certain volume and value.

Alexander Makarov 9 Sep 8, 2022
This project is based on the problem statement provided by the Minstry of HRD (India) for Smart India Hackathon '17.

This project is based on the problem statement provided by the Minstry of HRD (India) for Smart India Hackathon '17. As per the given problem statement, we need to solve the problem of bunching of marks at certain level, and problem of high scorers being at disadvantageous position due to lower competitive percentile.

Saransh Dave 4 Oct 13, 2022
This Magento extension provides a Real Full Page Caching for Magento powered by Varnish with support of Session-Based information caching (Cart, Customer Accounts, ...) via ESI includes

This Magento extension provides a Real Full Page Caching (FPC) for Magento powered by Varnish with support of Session-Based information caching (Cart, Customer Accounts, ...) via ESI includes

Hugues Alary 95 Feb 11, 2022
The Cache component provides an extended PSR-6 implementation for adding cache to your applications.

Symfony PSR-6 implementation for caching The Cache component provides an extended PSR-6 implementation for adding cache to your applications. It is de

Symfony 3.8k Jan 3, 2023
Error handler with PSR-7 support

Jasny Error Handler Error handler with PSR-7 support. Installation The Jasny Error Handler package is available on packagist. Install it using compose

Arnold Daniels 6 Jun 23, 2022
This repository includes direct links to Genshin Impact updates

GenshinRepository This repository includes direct links to Genshin Impact updates, with this, it allows you to download Genshin Impact updates without

Rifqi Arief 72 Jan 3, 2023
Rocket Web Prime theme based on Magento Blank that includes our most common customizations.

RW Prime - Magento 2 boilerplate theme RW Prime theme is based on Magento Blank and includes our most common customizations that we make on the majori

Rocket Web FED 37 Aug 8, 2022
Magento sample data includes a sample store, complete with more than 250 products

Magento sample data includes a sample store, complete with more than 250 products (about 200 of them are configurable products), categories, promotional price rules, CMS pages, banners, and so on. Sample data uses the Luma theme on the storefront.

Magento 203 Dec 16, 2022
NamelessMC is a free, easy to use & powerful website software for your Minecraft server, which includes a large range of features.

NamelessMC is a free, easy to use & powerful website software for your Minecraft server, which includes a large range of features

NamelessMC 519 Dec 31, 2022
YesilCMS is based on BlizzCMS and specifically adapted for VMaNGOS Core and includes new features and many bug fixes.

YesilCMS · YesilCMS is based on BlizzCMS and specifically adapted for VMaNGOS Core and includes new features and many bug fixes. Features In addition

yesilmen 12 Jan 4, 2023
This Kirby V3 Plugin brings snippets and blueprints together in one place. It includes useful tools that completely changing the way you work with Kirby: Fast and well organized.

Kirby Components Overview Do you love to make awesome projects with Kirby CMS? Do you also find it difficult to switch between snippets and blueprints

Roman Gsponer 6 May 31, 2023
Michael Pratt 307 Dec 23, 2022
The Assure Alliance support website. This website is based on Questions2Answers and is a forum for support using Biblical Tools

The Assure Alliance support website. This website is based on Questions2Answers and is a forum for support using Biblical Tools

United Bible Societies Institute for Computer Assisted Publishing 3 Jul 29, 2022
Simple yet powerful, PSR-compliant, Symfony-driven PHP Blog engine.

brodaty-blog ✒️ Simple Blog Engine based on pure Markdown files. ?? Works without database, caches HTML templates from Markdown files. ?? Fast and ext

Sebastian 3 Nov 15, 2022