Skip to content

Commit 65ea2dc

Browse files
Update errors exception example and add validation error handling example
1 parent 0af8741 commit 65ea2dc

File tree

1 file changed

+150
-12
lines changed

1 file changed

+150
-12
lines changed

core/errors.md

Lines changed: 150 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ API Platform Core allows to customize the HTTP status code sent to the clients w
55
```yaml
66
# app/config/config.yml
77

8-
services:
8+
api_platform:
99
# Map exceptions to HTTP status codes using the `exception_to_status` configuration key
1010
exception_to_status:
1111
# The 2 following exceptions are handled by default
@@ -32,37 +32,175 @@ final class ProductNotFoundException extends \Exception
3232
```php
3333
<?php
3434

35-
// src/AppBundle/Manager/CartManager.php
35+
// src/AppBundle/EventSubscriber/CartManager.php
3636

37-
namespace AppBundle\Manager;
37+
namespace AppBundle\EventSubscriber;
3838

39+
use ApiPlatform\Core\EventListener\EventPriorities;
3940
use AppBundle\Entity\Product;
4041
use AppBundle\Exception\ProductNotFoundException;
42+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
43+
use Symfony\Component\HttpFoundation\Request;
44+
use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
45+
use Symfony\Component\HttpKernel\KernelEvents;
4146

42-
final class CartManager
47+
final class ProductManager implements EventSubscriberInterface
4348
{
4449
private const DOESNOTEXISTS = 51;
4550
private const DEACTIVATED = 52;
4651
private const OUTOFSTOCK = 53;
4752

53+
public static function getSubscribedEvents()
54+
{
55+
return [
56+
KernelEvents::REQUEST => [['checkProductAvailability', EventPriorities::POST_DESERIALIZE]],
57+
];
58+
}
59+
60+
public function checkProductAvailability(GetResponseForControllerResultEvent $event)
61+
{
62+
$product = $event->getControllerResult();
63+
$method = $event->getRequest()->getMethod();
64+
65+
if (!$product instanceof Product || Request::METHOD_GET !== $method) {
66+
return;
67+
}
68+
69+
if (!$product->getVirtualStock()) {
70+
// Using internal codes for a better understanding of what's going on
71+
throw new ProductNotFoundException(self::OUTOFSTOCK);
72+
}
73+
}
74+
}
75+
```
76+
77+
The exception doesn't have to be a Symfony's `HttpException`. Any type of `Exception` can be thrown. The best part is that API Platform already takes care of how the error is handled and returned. For instance, if the API is configured to respond in JSON-LD, the error will be returned in this format as well.
78+
79+
```json
80+
{
81+
"@context": "/contexts/Error",
82+
"@type": "Error",
83+
"hydra:title": "An error occurred",
84+
"hydra:description": "53"
85+
}
86+
```
87+
88+
Is what you get, with an HTTP status code 404 as defined in the configuration.
89+
90+
## Validation errors
91+
92+
API Platform does handle the validation errors responses for you. You can define a Symfony supported constraint, or a custom constraint upon any `ApiResource` or it's properties.
93+
94+
```php
95+
<?php
96+
97+
// src/AppBundle/Entity/Product.php
98+
99+
namespace AppBundle\Entity;
100+
101+
use ApiPlatform\Core\Annotation\ApiResource;
102+
use Doctrine\ORM\Mapping as ORM;
103+
use Symfony\Component\Validator\Constraints as Assert;
104+
use AppBundle\Validator\Constraints as AppAssert;
105+
106+
/**
107+
*
108+
* @ApiResource
109+
* @ORM\Entity
110+
*/
111+
class Product
112+
{
113+
/**
114+
* @var int The id of this product.
115+
*
116+
* @ORM\Id
117+
* @ORM\GeneratedValue
118+
* @ORM\Column(type="integer")
119+
*/
120+
private $id;
121+
48122
/**
49-
* @param int $id
123+
* @var string The name of the product
50124
*
51-
* @throws ProductNotFoundException
125+
* @ORM\Column
126+
* @Assert\NotBlank
52127
*/
53-
public function addProductToCart(int $id)
128+
private name;
129+
130+
/**
131+
* @var ProductProperty[] Describe the product
132+
*
133+
* @ORM\Column(type="array")
134+
* @AppAssert\MinimalProperties
135+
*/
136+
private $properties;
137+
}
138+
```
139+
140+
```php
141+
<?php
142+
143+
// src/AppBundle/Validator/Constraints/MinimalProperties.php
144+
145+
namespace AppBundle\Validator\Constraints;
146+
147+
use Symfony\Component\Validator\Constraint;
148+
149+
/**
150+
* @Annotation
151+
*/
152+
class MinimalProperties extends Constraint
153+
{
154+
public $message = 'The product must have the minimal properties required (description, price)';
155+
156+
public function validatedBy()
54157
{
55-
$product = /*...*/;
158+
return get_class($this).'Validator';
159+
}
160+
}
161+
```
56162

57-
if (!$product->getVirtualStock()) {
58-
// Using internal codes for a better understanding of what's going on
59-
throw new ProductNotFoundException(self::NOTFOUND_OUTOFSTOCK);
163+
```php
164+
<?php
165+
166+
// src/AppBundle/Validator/Constraints/MinimalPropertiesValidator.php
167+
168+
namespace AppBundle\Validator\Constraints;
169+
170+
use Symfony\Component\Validator\Constraint;
171+
use Symfony\Component\Validator\ConstraintValidator;
172+
173+
/**
174+
* @Annotation
175+
*/
176+
final class MinimalPropertiesValidator extends ConstraintValidator
177+
{
178+
public function validate($value, Constraint $constraint)
179+
{
180+
if (!in_array('description', $value) || !in_array('price', $value)) {
181+
$this->context->buildViolation($constraint->message)
182+
->addViolation();
60183
}
61184
}
62185
}
63186
```
64187

65-
The exception doesn't have to be a Symfony's `HttpException`. Any type of `Exception` can be thrown. The best part is that API Platform already takes care of how the error is handled and returned. For instance the API is configured to respond in JSON-LD, the error will be returned in this format as well.
188+
API Platform will handle the error returned and adapt it's format according to the API configuration. If you did configured it to respond in JSON-LD. Your response would looks like:
189+
190+
```json
191+
{
192+
"@context": "/contexts/ConstraintViolationList",
193+
"@type": "ConstraintViolationList",
194+
"hydra:title": "An error occurred",
195+
"hydra:description": "properties: The product must have the minimal properties required (description, price)",
196+
"violations": [
197+
{
198+
"propertyPath": "properties",
199+
"message": "The product must have the minimal properties required (description, price)"
200+
}
201+
]
202+
}
203+
```
66204

67205
Previous chapter: [Pagination](pagination.md)
68206

0 commit comments

Comments
 (0)