Symfony custom error exception response
When we start writing API we need own Error Exception depended our logic and we want pretty error response to client when our logic exception throw error
Let’s imagine we need to check before checkout that are goods available in stock.
create own exception
<?php
class OutOfStockException extends \Exception {
private int $product;
private int $count;
private int $shortageCount;
public function __construct(int $product, int $count, int $shortageCount)
{
parent::__construct('Product is out of stock');
$this->product = $product;
$this->count = $count;
$this->shortageCount = $shortageCount;
}
public function getProduct(): int
{
return $this->product;
}
public function getCount(): int
{
return $this->count;
}
public function getShortageCount(): int
{
return $this->shortageCount;
}
}
The first method is catch error and response error data to client in controller action
class OrderController extends AbstractController
{
public function checkoutAction()
{
try {
// checkout logic will be here
} catch (OutOfStockException $e) {
return JsonResponse::create([
'product' => $e->getProduct(),
'count' => $e->getCount(),
'shortageCount' => $e->getShortageCount(),
'message' => $e->getMessage(),
]);
}
}
}
The next method which are very clearly and wisely by using Symfony event listener
we create Interface for grouping Exceptions
interface ListenableExceptionInterface
{
public function toArray(): array;
}
And our class should be implement this interface
create event listener class for catch our specific exception
<?php
class OutOfStockException extends \Exception implements ListenableExceptionInterface {
// above body getter and constructor code will be here
public function toArray(): array
{
return [
'product' => $this->getProduct(),
'count' => $this->getCount(),
'shortageCount' => $this->getShortageCount(),
'message' => $this->getMessage(),
];
}
}
And our listener catch all exceptions which was implemented by ListenableExceptionInterface
class AdvanceExceptionListener
{
public function onKernelException(ExceptionEvent $event)
{
$exception = $event->getException();
if (!$exception instanceof ListenableExceptionInterface) {
return;
}
$response = new JsonResponse($exception->toArray(), $exception->getCode());
$event->setResponse($response);
}
}
in our service we throw exception
<?php
class CheckoutManager {
public function checkout(Product $product, int $count) {
if($product->getCount() < $count){
throw new OutOfStockException($product->getId(), $count, $count - $product->getCount());
}
}
}
We don’t need catch exception in out controller action, our Listener automatic listen this exception and return response