Skip to content

Commit

Permalink
[OpenApi] more info when api exception
Browse files Browse the repository at this point in the history
  • Loading branch information
mpoiriert committed Jun 21, 2024
1 parent 5aeb4c7 commit 45229cd
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 53 deletions.
31 changes: 10 additions & 21 deletions packages/open-api/EventListener/ResponseApiExceptionListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,18 @@
use Draw\Component\OpenApi\Schema\Response;
use Draw\Component\OpenApi\Schema\Schema;
use Symfony\Component\DependencyInjection\Attribute\TaggedIterator;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\Validator\ConstraintViolation;
use Symfony\Component\Validator\ConstraintViolationInterface;
use Symfony\Component\Validator\ConstraintViolationList;

final class ResponseApiExceptionListener implements EventSubscriberInterface
final class ResponseApiExceptionListener
{
public static function getSubscribedEvents(): array
{
return [
ExceptionEvent::class => ['onKernelException', 255],
PreDumpRootSchemaEvent::class => ['addErrorDefinition'],
];
}

public function __construct(
/**
* @var ErrorToHttpCodeConverterInterface[]
* @var iterable<ErrorToHttpCodeConverterInterface>
*/
#[TaggedIterator(ErrorToHttpCodeConverterInterface::class)]
private iterable $errorToHttpCodeConverters = [],
Expand All @@ -38,6 +30,7 @@ public function __construct(
$this->errorToHttpCodeConverters ??= new ConfigurableErrorToHttpCodeConverter();
}

#[AsEventListener]
public function addErrorDefinition(PreDumpRootSchemaEvent $event): void
{
$root = $event->getSchema();
Expand Down Expand Up @@ -88,6 +81,7 @@ public function addErrorDefinition(PreDumpRootSchemaEvent $event): void
}
}

#[AsEventListener(priority: 255)]
public function onKernelException(ExceptionEvent $event): void
{
$request = $event->getRequest();
Expand All @@ -108,9 +102,7 @@ public function onKernelException(ExceptionEvent $event): void
$data[$this->violationKey] = $this->getConstraintViolationData($error);
}

if ($this->debug) {
$data['detail'] = $this->getExceptionDetail($error);
}
$data['detail'] = $this->getExceptionDetail($error);

$event->setResponse(
new JsonResponse(
Expand Down Expand Up @@ -143,10 +135,7 @@ private function getConstraintViolationData(ConstraintViolationListException $ex
return $errors;
}

/**
* @return mixed
*/
private function getConstraintPayload(ConstraintViolationInterface $constraintViolation)
private function getConstraintPayload(ConstraintViolationInterface $constraintViolation): mixed
{
if (!$constraintViolation instanceof ConstraintViolation) {
return null;
Expand All @@ -173,10 +162,10 @@ private function getExceptionDetail(\Throwable $e): array
foreach (explode("\n", $e->getTraceAsString()) as $line) {
$result['stack'][] = $line;
}
}

if ($previous = $e->getPrevious()) {
$result['previous'] = $this->getExceptionDetail($previous);
}
if ($previous = $e->getPrevious()) {
$result['previous'] = $this->getExceptionDetail($previous);
}

return $result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
use Draw\Component\OpenApi\Schema\Root;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\TestCase;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
Expand Down Expand Up @@ -39,7 +38,9 @@ protected function setUp(): void
$this->httpKernel = $this->createMock(HttpKernelInterface::class),
$this->request = $this->createMock(Request::class),
HttpKernelInterface::MAIN_REQUEST,
$this->exception = $this->createMock(\Exception::class)
$this->exception = new \Exception(
previous: new \Exception()
)
);

$this->request
Expand All @@ -48,25 +49,6 @@ protected function setUp(): void
->willReturn('json');
}

public function testConstruct(): void
{
static::assertInstanceOf(
EventSubscriberInterface::class,
$this->object
);
}

public function testSubscribedEvents(): void
{
static::assertSame(
[
ExceptionEvent::class => ['onKernelException', 255],
PreDumpRootSchemaEvent::class => ['addErrorDefinition'],
],
$this->object::getSubscribedEvents()
);
}

/**
* todo Improve test asser on this.
*/
Expand Down Expand Up @@ -135,23 +117,45 @@ public function testOnKernelExceptionJsonResponse(): void

public function testOnKernelExceptionDefaultDebugFalse(): void
{
$exceptionDetail = json_decode(
$this->onKernelException()->getContent(),
true,
512,
\JSON_THROW_ON_ERROR
)['detail'];

static::assertArrayNotHasKey(
'detail',
json_decode($this->onKernelException()->getContent(), true, 512, \JSON_THROW_ON_ERROR)
'stack',
$exceptionDetail
);
}

public function testOnKernelExceptionDebugFalse(): void
{
static::assertArrayNotHasKey(
'detail',
json_decode(
$this->onKernelException(
new ResponseApiExceptionListener(debug: false)
)->getContent(),
true,
512,
\JSON_THROW_ON_ERROR
$exceptionDetail = json_decode(
$this->onKernelException(
new ResponseApiExceptionListener(debug: false)
)->getContent(),
true,
512,
\JSON_THROW_ON_ERROR
)['detail'];

$expectedKeys = ['class', 'message', 'code', 'file', 'line', 'previous'];

static::assertEmpty(
$extraKeys = array_diff(array_keys($exceptionDetail), $expectedKeys),
sprintf(
'Unexpected keys: %s',
implode(', ', $extraKeys)
)
);

static::assertEmpty(
$missingKeys = array_diff($expectedKeys, array_keys($exceptionDetail)),
sprintf(
'Missing keys: %s',
implode(', ', $missingKeys)
)
);
}
Expand Down
29 changes: 29 additions & 0 deletions tests/OpenApi/EventListener/ResponseApiExceptionListenerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace App\Tests\OpenApi\EventListener;

use Draw\Bundle\TesterBundle\EventDispatcher\EventListenerTestTrait;
use Draw\Bundle\TesterBundle\PHPUnit\Extension\SetUpAutowire\AutowiredInterface;
use Draw\Bundle\TesterBundle\PHPUnit\Extension\SetUpAutowire\AutowireService;
use Draw\Component\OpenApi\Event\PreDumpRootSchemaEvent;
use Draw\Component\OpenApi\EventListener\ResponseApiExceptionListener;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;

class ResponseApiExceptionListenerTest extends KernelTestCase implements AutowiredInterface
{
use EventListenerTestTrait;

#[AutowireService]
private ResponseApiExceptionListener $object;

public function test(): void
{
$this->assertEventListenersRegistered(
$this->object::class,
[
'kernel.exception' => ['onKernelException'],
PreDumpRootSchemaEvent::class => ['addErrorDefinition'],
]
);
}
}

0 comments on commit 45229cd

Please sign in to comment.