Skip to content

Commit 1d8ed99

Browse files
authored
Merge pull request #2 from lcobucci/improve-documentation
Improve documentation
2 parents 9353cdc + f040c18 commit 1d8ed99

14 files changed

+218
-4
lines changed

README.md

+171-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
[![Unstable Version](https://img.shields.io/packagist/vpre/lcobucci/error-handling-middleware.svg?style=flat-square)](https://packagist.org/packages/lcobucci/error-handling-middleware)
66

77
![Branch master](https://img.shields.io/badge/branch-master-brightgreen.svg?style=flat-square)
8-
[![Build Status](https://img.shields.io/travis/lcobucci/error-handling-middleware/master.svg?style=flat-square)](http://travis-ci.org/#!/lcobucci/error-handling-middleware)
8+
[![Build Status](https://img.shields.io/travis/lcobucci/error-handling-middleware/master.svg?style=flat-square)](http://travis-ci.org/lcobucci/error-handling-middleware)
99
[![Scrutinizer Code Quality](https://img.shields.io/scrutinizer/g/lcobucci/error-handling-middleware/master.svg?style=flat-square)](https://scrutinizer-ci.com/g/lcobucci/error-handling-middleware/?branch=master)
1010
[![Code Coverage](https://img.shields.io/scrutinizer/coverage/g/lcobucci/error-handling-middleware/master.svg?style=flat-square)](https://scrutinizer-ci.com/g/lcobucci/error-handling-middleware/?branch=master)
1111

@@ -22,16 +22,183 @@ flexibility to solve this problem.
2222

2323
## Installation
2424

25-
This package is available on [Packagist](http://packagist.org/packages/lcobucci/error-handling-middleware),
26-
and we recommend you to install it using [Composer](http://getcomposer.org):
25+
This package is available on [Packagist](https://packagist.org/packages/lcobucci/error-handling-middleware),
26+
and we recommend you to install it using [Composer](https://getcomposer.org):
2727

2828
```shell
2929
composer require lcobucci/error-handling-middleware
3030
```
3131

3232
## Usage
3333

34-
TDB
34+
In order to us this package you must add the middleware to your pipeline, configuring
35+
the desired behaviour (debug info strategy and status code extraction strategy).
36+
37+
Once this is set you'll be able to have your errors/exceptions converted into the
38+
correct HTTP responses.
39+
40+
### Middleware position
41+
42+
This package provides two middleware for handling errors: error logging and error
43+
conversion.
44+
45+
They are designed to be used in the very beginning of the HTTP middleware pipeline,
46+
just after the [content negotiation](https://github.com/lcobucci/content-negotiation-middleware) one:
47+
48+
```php
49+
<?php
50+
use Lcobucci\ContentNegotiation\ContentTypeMiddleware;
51+
use Lcobucci\ErrorHandling\ErrorConversionMiddleware;
52+
use Lcobucci\ErrorHandling\ErrorLoggingMiddleware;
53+
54+
// In a Zend Expressive application, it would look like this:
55+
$application->pipe(ContentTypeMiddleware::fromRecommendedSettings( /* ... */ )); // Very first middleware
56+
$application->pipe(new ErrorConversionMiddleware( /* ... */ ));
57+
$application->pipe(new ErrorLoggingMiddleware( /* ... */ ));
58+
59+
// all other middleware.
60+
```
61+
62+
With that we'll be able to perform the logging and conversion in the correct order,
63+
delegating the content negotiation and formatting to `ContentTypeMiddleware` - using
64+
the configured formatters.
65+
66+
#### Important
67+
68+
The `ErrorConversionMiddleware` uses an `UnformattedResponse` to let the
69+
`ContentTypeMiddleware` perform the formatting. Make sure you have configured
70+
formatters for the MIME types `application/problem+json` and/or
71+
`application/problem+xml`.
72+
73+
It also makes the error/exception available in the `error` attribute of the response,
74+
so you may access it (if needed) by using another middleware between
75+
`ErrorConversionMiddleware` and `ContentTypeMiddleware`.
76+
77+
### Configuring the conversion middleware behaviour
78+
79+
There're two extension points that you can use for that: debug info strategy and
80+
status code extraction strategy.
81+
82+
You can also configure the response body attributes by implementing certain interfaces
83+
in your exceptions.
84+
85+
#### Debug info strategy
86+
87+
This defines how the `_debug` property should be generated in the response body.
88+
We provide two default implementations - one designed for production mode and the
89+
other for development mode.
90+
91+
To configure this you must pass the desired implementation (or a customised one) as
92+
the second argument of the `ErrorConversionMiddleware` constructor.
93+
94+
To provide your own implementation you need to create a class that implements the
95+
`DebugInfoStrategy` interface.
96+
97+
#### Status code extraction strategy
98+
99+
This defines how the translation from error/exception to HTTP status code should
100+
be done. We provide a single default implementation for that, which is based on
101+
class maps.
102+
103+
To configure this you must pass the desired implementation (or a customised one) as
104+
the third argument of the `ErrorConversionMiddleware` constructor.
105+
106+
To provide your own implementation you need to create a class that implements the
107+
`StatusCodeExtractionStrategy` interface.
108+
109+
##### Default class map
110+
111+
The default map uses the marker interfaces in this packages to perform such translation.
112+
If the error/exception doesn't implement any of the marker interfaces, the error/exception
113+
code will be used (when it's different than zero), or fallback to the status code
114+
500 (Internal Server Error).
115+
116+
The default map is:
117+
118+
* `Lcobucci\ErrorHandling\Problem\InvalidRequest` -> `400`
119+
* `Lcobucci\ErrorHandling\Problem\AuthorizationRequired` -> `401`
120+
* `Lcobucci\ErrorHandling\Problem\Forbidden` -> `403`
121+
* `Lcobucci\ErrorHandling\Problem\ResourceNotFound` -> `404`
122+
* `Lcobucci\ErrorHandling\Problem\Conflict` -> `409`
123+
* `Lcobucci\ErrorHandling\Problem\ResourceNoLongerAvailable` -> `410`
124+
* `Lcobucci\ErrorHandling\Problem\UnprocessableRequest` -> `422`
125+
* `Lcobucci\ErrorHandling\Problem\ServiceUnavailable`-> `503`
126+
127+
This allows us to create our own exceptions that are automatically converted to the
128+
correct status code:
129+
130+
```php
131+
<?php
132+
declare(strict_types=1);
133+
134+
namespace My\Fancy\App\UserManagement;
135+
136+
use Lcobucci\ErrorHandling\Problem\ResourceNotFound;
137+
use RuntimeException;
138+
139+
final class UserNotFound extends RuntimeException implements ResourceNotFound
140+
{
141+
}
142+
```
143+
144+
**Important**: you SHOULD NOT implement more than one of the marker interfaces,
145+
otherwise you may have unexpected results.
146+
147+
#### Customising the response body properties
148+
149+
With this library, you may modify the `type` and `title` properties of the generated
150+
response and also append new members to it.
151+
152+
That's done by implementing the `Typed`, `Titled`, and/or `Detailed` interfaces -
153+
you don't necessarily need to implement all of them, only the ones you want.
154+
155+
The example below shows how to represent one of the samples in the
156+
[RFC 7807](https://tools.ietf.org/html/rfc7807#section-3):
157+
158+
```php
159+
<?php
160+
declare(strict_types=1);
161+
162+
namespace My\Fancy\App\UserManagement;
163+
164+
use Lcobucci\ErrorHandling\Problem\Forbidden;
165+
use Lcobucci\ErrorHandling\Problem\Typed;
166+
use Lcobucci\ErrorHandling\Problem\Titled;
167+
use Lcobucci\ErrorHandling\Problem\Detailed;
168+
use RuntimeException;
169+
use function sprintf;
170+
171+
final class InsufficientCredit extends RuntimeException implements Forbidden, Typed, Titled, Detailed
172+
{
173+
private $currentBalance;
174+
175+
public static function forPurchase(int $currentBalance, int $cost): self
176+
{
177+
$exception = new self(sprintf('Your current balance is %d, but that costs %d.', $currentBalance, $cost));
178+
$exception->currentBalance = $currentBalance;
179+
180+
return $exception;
181+
}
182+
183+
public function getTypeUri(): string
184+
{
185+
return 'https://example.com/probs/out-of-credit';
186+
}
187+
188+
public function getTitle(): string
189+
{
190+
return 'You do not have enough credit.';
191+
}
192+
193+
/**
194+
* {@inheritDoc}
195+
*/
196+
public function getExtraDetails(): array
197+
{
198+
return ['balance' => $this->currentBalance]; // you might add "instance" and "accounts" too :)
199+
}
200+
}
201+
```
35202

36203
## License
37204

src/DebugInfoStrategy.php

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55

66
use Throwable;
77

8+
/**
9+
* Defines how the debug information should be extracted from an error/exception
10+
*/
811
interface DebugInfoStrategy
912
{
1013
/**

src/Problem/AuthorizationRequired.php

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55

66
use Throwable;
77

8+
/**
9+
* Marker interface to be used in exceptions related to missing auth information (credentials or valid access token)
10+
*/
811
interface AuthorizationRequired extends Throwable
912
{
1013
}

src/Problem/Conflict.php

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55

66
use Throwable;
77

8+
/**
9+
* Marker interface to be used in exceptions related to resource conflicts (version mismatch or duplicated data)
10+
*/
811
interface Conflict extends Throwable
912
{
1013
}

src/Problem/Detailed.php

+5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55

66
use Throwable;
77

8+
/**
9+
* Provides extension members to the problem details
10+
*
11+
* @see https://tools.ietf.org/html/rfc7807#section-3.2
12+
*/
813
interface Detailed extends Throwable
914
{
1015
/**

src/Problem/Forbidden.php

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55

66
use Throwable;
77

8+
/**
9+
* Marker interface to be used in exceptions related to forbidden operations (lack of permission)
10+
*/
811
interface Forbidden extends Throwable
912
{
1013
}

src/Problem/InvalidRequest.php

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55

66
use Throwable;
77

8+
/**
9+
* Marker interface to be used in exceptions related to malformed requests (syntax issues)
10+
*/
811
interface InvalidRequest extends Throwable
912
{
1013
}

src/Problem/ResourceNoLongerAvailable.php

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55

66
use Throwable;
77

8+
/**
9+
* Marker interface to be used in exceptions related to removed resource (removed/archived items)
10+
*/
811
interface ResourceNoLongerAvailable extends Throwable
912
{
1013
}

src/Problem/ResourceNotFound.php

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55

66
use Throwable;
77

8+
/**
9+
* Marker interface to be used in exceptions related to non-existing resources
10+
*/
811
interface ResourceNotFound extends Throwable
912
{
1013
}

src/Problem/ServiceUnavailable.php

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55

66
use Throwable;
77

8+
/**
9+
* Marker interface to be used in exceptions related to availability issues (maintenance or dependency issues)
10+
*/
811
interface ServiceUnavailable extends Throwable
912
{
1013
}

src/Problem/Titled.php

+7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@
55

66
use Throwable;
77

8+
/**
9+
* Provides a custom (human-readable) summary of the problem
10+
*
11+
* The provided title SHOULD NOT vary from occurrence to occurrence.
12+
*
13+
* @see https://tools.ietf.org/html/rfc7807#section-3.1
14+
*/
815
interface Titled extends Throwable
916
{
1017
public function getTitle(): string;

src/Problem/Typed.php

+5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55

66
use Throwable;
77

8+
/**
9+
* Provides a custom URI for the documentation of the problem
10+
*
11+
* @see https://tools.ietf.org/html/rfc7807#section-3.1
12+
*/
813
interface Typed extends Throwable
914
{
1015
public function getTypeUri(): string;

src/Problem/UnprocessableRequest.php

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55

66
use Throwable;
77

8+
/**
9+
* Marker interface to be used in exceptions related to syntactically correct but semantically invalid requests
10+
*/
811
interface UnprocessableRequest extends Throwable
912
{
1013
}

src/StatusCodeExtractionStrategy.php

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55

66
use Throwable;
77

8+
/**
9+
* Defines how the translation of errors/exceptions into HTTP status codes should happen
10+
*/
811
interface StatusCodeExtractionStrategy
912
{
1013
public function extractStatusCode(Throwable $error): int;

0 commit comments

Comments
 (0)