10000 Add error helpers to ResponsesHelper. · rubinred/laravel-json-api@1460e52 · GitHub
[go: up one dir, main page]

Skip to content

Commit 1460e52

Browse files
committed
Add error helpers to ResponsesHelper.
1 parent c664222 commit 1460e52

File tree

4 files changed

+180
-3
lines changed

4 files changed

+180
-3
lines changed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,9 +314,16 @@ The available helpers are:
314314
| `content` | Send content (resource object, null, or collection) |
315315
| `created` | Send a resource created response (encoded object, location header and 201 status) |
316316
| `relationship` | Send a relationship response (encoded identifier, null, or collection of identifiers) |
317+
| `error` | Send a response with a single JSON API error object |
318+
| `errors` | Send a response with multiple JSON API error objects |
317319

318320
See the class for the parameters that each helper method accepts.
319321

322+
Note that sending error responses can also be achieved by throwing exceptions (see below). Throwing errors
323+
is preferable if you want to stop execution, and/or if you want your exception handler to decide if the exception
324+
should be logged. Using the reply helper's `error` and `errors` methods will not send an exception to your exception
325+
handler.
326+
320327
The reply method is added to the controller via the `ReplyTrait`.
321328

322329
### Exception Handling

src/Http/Responses/ResponsesHelper.php

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@
1818

1919
namespace CloudCreativity\JsonApi\Http\Responses;
2020

21+
use CloudCreativity\JsonApi\Contracts\Error\ErrorCollectionInterface;
2122
use CloudCreativity\JsonApi\Contracts\Integration\EnvironmentInterface;
2223
use Illuminate\Http\Response;
2324
use Illuminate\Support\Collection;
25+
use Neomerx\JsonApi\Contracts\Document\ErrorInterface;
2426
use Neomerx\JsonApi\Contracts\Encoder\EncoderInterface;
2527
use Neomerx\JsonApi\Contracts\Responses\ResponsesInterface;
2628

@@ -179,6 +181,50 @@ public function relationship(
179181
return $this->respond(Response::HTTP_OK, $content, $headers);
180182
}
181183

184+
/**
185+
* Send a single JSON API error object as a response.
186+
*
187+
* The status code will be taken directly from the provided error object using the `ErrorInterface::getStatus()`
188+
* method. If that method returns a falsey value, then the status code will default to 500.
189+
*
190+
* @param ErrorInterface $error
191+
* @param array $headers
192+
* @return Response
193+
*/
194+
public function error(ErrorInterface $error, array $headers = [])
195+
{
196+
$statusCode = $error->getStatus() ?: Response::HTTP_INTERNAL_SERVER_ERROR;
197+
198+
$content = $this
199+
->getEncoder()
200+
->encodeError($error);
201+
202+
return $this->respond($statusCode, $content, $headers);
203+
}
204+
205+
/**
206+
* @param ErrorInterface[]|ErrorCollectionInterface $errors
207+
* @param $statusCode
208+
* if not provided, defaults to 500 or the ErrorCollectionInterface status.
209+
* @param array $headers
210+
* @return Response
211+
*/
212+
public function errors($errors, $statusCode = null, array $headers = [])
213+
{
214+
if ($errors instanceof ErrorCollectionInterface) {
215+
$statusCode = is_null($statusCode) ? $errors->getStatus() : $statusCode;
216+
$errors = $errors->getAll();
217+
} elseif (is_null($statusCode)) {
218+
$statusCode = Response::HTTP_INTERNAL_SERVER_ERROR;
219+
}
220+
221+
$content = $this
222+
->getEncoder()
223+
->encodeErrors($errors);
224+
225+
return $this->respond($statusCode, $content, $headers);
226+
}
227+
182228
/**
183229
* @param $statusCode
184230
* @param string|null $content
@@ -201,15 +247,15 @@ public function respond($statusCode, $content = null, array $headers = [])
201247
/**
202248
* @return EncoderInterface
203249
*/
204-
public function getEncoder()
250+
private function getEncoder()
205251
{
206252
return $this->environment->getEncoder();
207253
}
208254

209255
/**
210256
* @return \Neomerx\JsonApi\Contracts\Parameters\ParametersInterface
211257
*/
212-
public function getEncodingParameters()
258+
private function getEncodingParameters()
213259
{
214260
return $this->environment->getParameters();
215261
}

src/Integration/LaravelIntegration.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public function getHeader($name)
9595
* @param int $statusCode
9696
* @param array $headers
9797
*
98-
* @return mixed
98+
* @return Response
9999
*/
100100
public function createResponse($content, $statusCode, array $headers)
101101
{
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
<?php
2+
3+
namespace CloudCreativity\JsonApi\Http\Responses;
4+
5+
use CloudCreativity\JsonApi\Contracts\Error\ErrorObjectInterface;
6+
use CloudCreativity\JsonApi\Error\ErrorCollection;
7+
use CloudCreativity\JsonApi\Error\ErrorObject;
8+
use CloudCreativity\JsonApi\Integration\LaravelIntegration;
9+
use Illuminate\Http\Request;
10+
use Illuminate\Http\Response;
11+
use Neomerx\JsonApi\Encoder\Encoder;
12+
use Neomerx\JsonApi\Parameters\EncodingParameters;
13+
use CloudCreativity\JsonApi\Contracts\Integration\EnvironmentInterface;
14+
use Neomerx\JsonApi\Parameters\Headers\MediaType;
15+
use Neomerx\JsonApi\Responses\Responses;
16+
17+
class ResponsesHelperTest extends \PHPUnit_Framework_TestCase
18+
{
19+
20+
/**
21+
* @var Encoder
22+
*/
23+
private $encoder;
24+
25+
/**
26+
* @var \PHPUnit_Framework_MockObject_MockObject
27+
*/
28+
private $environment;
29+
30+
/**
31+
* @var ResponsesHelper
32+
*/
33+
private $helper;
34+
35+
protected function setUp()
36+
{
37+
$this->encoder = Encoder::instance([]);
38+
$encodingParameters = new EncodingParameters(['foo']);
39+
$mediaType = new MediaType(MediaType::JSON_API_TYPE, MediaType::JSON_API_SUB_TYPE);
40+
41+
$environment = $this->getMock(EnvironmentInterface::class);
42+
$environment->method('getEncoder')->willReturn($this->encoder);
43+
$environment->method('getParameters')->willReturn($encodingParameters);
44+
$environment->method('getEncoderMediaType')->willReturn($mediaType);
45+
$this->environment = $environment;
46+
47+
$integration = new LaravelIntegration(new Request());
48+
$responses = new Responses($integration);
49+
50+
/** @var EnvironmentInterface $environment */
51+
$this->helper = new ResponsesHelper($environment, $responses);
52+
}
53+
54+
public function testError()
55+
{
56+
$error = new ErrorObject([
57+
ErrorObject::TITLE => 'Test error',
58+
ErrorObject::DETAIL => 'My custom error',
59+
ErrorObject::CODE => 'foo-bar',
60+
ErrorObject::STATUS => 501,
61+
]);
62+
63+
$expected = new Response($this->encoder->encodeError($error), 501, [
64+
'Content-Type' => MediaType::JSON_API_MEDIA_TYPE,
65+
]);
66+
67+
$this->assertEquals($expected, $this->helper->error($error));
68+
69+
$expected->header('X-Custom', 'Foo');
70+
71+
$this->assertEquals($expected, $this->helper->error($error, [
72+
'X-Custom' => 'Foo',
73+
]));
74+
}
75+
76+
public function testErrorsWithArray()
77+
{
78+
$errors = [new ErrorObject([
79+
ErrorObject::TITLE => 'Error',
80+
ErrorObject::CODE => 'foo-bar',
81+
ErrorObject::STATUS => 418,
82+
])];
83+
84+
$content = $this->encoder->encodeErrors($errors);
85+
86+
$expected = new Response($content, 500, [
87+
'Content-Type' => MediaType::JSON_API_MEDIA_TYPE,
88+
]);
89+
90+
$this->assertEquals($expected, $this->helper->errors($errors));
91+
92+
$expected->setStatusCode(418);
93+
$expected->header('X-Custom', 'Foo');
94+
95+
$this->assertEquals($expected, $this->helper->errors($errors, 418, [
96+
'X-Custom' => 'Foo',
97+
]));
98+
}
99+
100+
public function testErrorsWithCollection()
101+
{
102+
$errors = new ErrorCollection();
103+
$errors->error([
104+
ErrorObject::TITLE => 'Error',
105+
ErrorObject::DETAIL => 'Foo',
106+
ErrorObject::STATUS => 418,
107+
]);
108+
109+
$content = $this->encoder->encodeErrors($errors->getAll());
110+
111+
$expected = new Response($content, $errors->getStatus(), [
112+
'Content-Type' => MediaType::JSON_API_MEDIA_TYPE,
113+
]);
114+
115+
$this->assertEquals($expected, $this->helper->errors($errors));
116+
117+
$expected->setStatusCode(499);
118+
$expected->header('X-Custom', 'Foo');
119+
120+
$this->assertEquals($expected, $this->helper->errors($errors, 499, [
121+
'X-Custom' => 'Foo',
122+
]));
123+
}
124+
}

0 commit comments

Comments
 (0)
0