Skip to content

Commit f040c18

Browse files
committed
Add information on how this library should be used
1 parent 1ae022c commit f040c18

File tree

1 file changed

+168
-1
lines changed

1 file changed

+168
-1
lines changed

README.md

Lines changed: 168 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,174 @@ composer require lcobucci/error-handling-middleware
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

0 commit comments

Comments
 (0)