Skip to content
Snippets Groups Projects
Commit 1e3134ff authored by Dave Long's avatar Dave Long Committed by Harumi Jang
Browse files

Issue #3470995 by longwave, traviscarden, wim leers, effulgentsia: OpenAPI...

Issue #3470995 by longwave, traviscarden, wim leers, effulgentsia: OpenAPI validation errors must be provided as a JSON response
parent f129bc14
No related branches found
Tags 1.0.2
1 merge request!321#3470995: OpenAPI validation errors must be provided as a JSON response
Pipeline #290059 passed
services:
_defaults:
autoconfigure: true
autowire: true
Drupal\experience_builder\ShapeMatcher\SdcPropToFieldTypePropMatcher:
public: true
......@@ -66,6 +67,7 @@ services:
class: Drupal\experience_builder\Theme\XBThemeNegotiator
tags:
- { name: theme_negotiator }
Drupal\experience_builder\EventSubscriber\ApiExceptionSubscriber: ~
# Controllers.
Drupal\experience_builder\Controller\ExperienceBuilderController: {}
......
<?php
namespace Drupal\experience_builder\EventSubscriber;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\KernelEvents;
/**
* Handle exceptions for Experience Builder API routes.
*/
final class ApiExceptionSubscriber implements EventSubscriberInterface {
public function __construct(
private readonly RouteMatchInterface $routeMatch,
private readonly ConfigFactoryInterface $configFactory,
private readonly AccountInterface $currentUser,
) {}
/**
* Handles exceptions and converts them to JSON responses.
*
* @param \Symfony\Component\HttpKernel\Event\ExceptionEvent $event
* The event to process.
*/
public function onException(ExceptionEvent $event): void {
if (str_starts_with($this->routeMatch->getRouteName() ?? '', 'experience_builder.api.')) {
$response = [];
$exception = $event->getThrowable();
$response['message'] = $exception->getMessage();
// The stack trace may contain sensitive information. Only show it to
// authorized users.
// @see \Drupal\jsonapi\Normalizer\HttpExceptionNormalizer::buildErrorObjects()
$is_verbose_reporting = $this->configFactory->get('system.logging')->get('error_level') === ERROR_REPORTING_DISPLAY_VERBOSE;
$site_report_access = $this->currentUser->hasPermission('access site reports');
if ($site_report_access && $is_verbose_reporting) {
$response += [
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'trace' => $exception->getTrace(),
];
}
$event->setResponse(new JsonResponse($response, Response::HTTP_INTERNAL_SERVER_ERROR));
}
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents(): array {
// Lower than the priority of \Drupal\Core\EventSubscriber\ExceptionJsonSubscriber.
$events[KernelEvents::EXCEPTION][] = ['onException', 50];
return $events;
}
}
......@@ -41,7 +41,11 @@ class EntityFormControllerTest extends FunctionalTestBase {
// Try to retrieve the form using the new form mode before it is created.
$this->drupalGet($new_form_mode_path);
$assert->statusCodeEquals(500);
$assert->pageTextContains('The "mode2" form display was not found');
$assert->responseHeaderEquals('Content-Type', 'application/json');
$json = json_decode($this->getSession()->getPage()->getContent());
$this->assertSame('The "mode2" form display was not found', $json->message);
// We are logged in as user 1 so we should see the trace.
$this->assertObjectHasProperty('trace', $json);
$user = $this->drupalCreateUser(['administer display modes', 'administer node form display', 'access administration pages']);
$this->assertInstanceOf(User::class, $user);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment