class ResourceResponseValidator
Same name in this branch
- 11.x core/modules/jsonapi/src/EventSubscriber/ResourceResponseValidator.php \Drupal\jsonapi\EventSubscriber\ResourceResponseValidator
Same name and namespace in other branches
- 10 core/modules/jsonapi/src/EventSubscriber/ResourceResponseValidator.php \Drupal\jsonapi\EventSubscriber\ResourceResponseValidator
- 9 core/modules/jsonapi/src/EventSubscriber/ResourceResponseValidator.php \Drupal\jsonapi\EventSubscriber\ResourceResponseValidator
- 8.9.x core/modules/jsonapi/src/EventSubscriber/ResourceResponseValidator.php \Drupal\jsonapi\EventSubscriber\ResourceResponseValidator
Response subscriber that validates a JSON:API response.
This must run after ResourceResponseSubscriber.
@internal JSON:API maintains no PHP API. The API is the HTTP API. This class may change at any time and could break any dependencies on it.
Hierarchy
- class \Drupal\jsonapi_response_validator\EventSubscriber\ResourceResponseValidator implements \Symfony\Component\EventDispatcher\EventSubscriberInterface
Expanded class hierarchy of ResourceResponseValidator
See also
https://www.drupal.org/project/drupal/issues/3032787
\Drupal\rest\EventSubscriber\ResourceResponseSubscriber
1 file declares its use of ResourceResponseValidator
- ResourceResponseValidatorTest.php in core/
modules/ jsonapi/ tests/ modules/ jsonapi_response_validator/ tests/ src/ Unit/ EventSubscriber/ ResourceResponseValidatorTest.php
File
-
core/
modules/ jsonapi/ tests/ modules/ jsonapi_response_validator/ src/ EventSubscriber/ ResourceResponseValidator.php, line 30
Namespace
Drupal\jsonapi_response_validator\EventSubscriberView source
class ResourceResponseValidator implements EventSubscriberInterface {
/**
* The schema validator.
*
* @var \JsonSchema\Validator
*/
protected Validator $validator;
/**
* Constructs a ResourceResponseValidator object.
*
* @param \Psr\Log\LoggerInterface $logger
* The JSON:API logger channel.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $moduleHandler
* The module handler.
* @param string $appRoot
* The application's root file path.
*/
public function __construct(protected LoggerInterface $logger, protected ModuleHandlerInterface $moduleHandler, protected string $appRoot) {
$this->validator = new Validator();
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() : array {
$events[KernelEvents::RESPONSE][] = [
'onResponse',
];
return $events;
}
/**
* Validates JSON:API responses.
*
* @param \Symfony\Component\HttpKernel\Event\ResponseEvent $event
* The event to process.
*/
public function onResponse(ResponseEvent $event) : void {
$response = $event->getResponse();
if (!str_contains($response->headers
->get('Content-Type', ''), 'application/vnd.api+json')) {
return;
}
// Wraps validation in an assert to prevent execution in production.
assert($this->validateResponse($response, $event->getRequest()), 'A JSON:API response failed validation (see the logs for details). Report this in the Drupal issue queue at https://www.drupal.org/project/issues/drupal');
}
/**
* Validates a response against the JSON:API specification.
*
* @param \Symfony\Component\HttpFoundation\Response $response
* The response to validate.
* @param \Symfony\Component\HttpFoundation\Request $request
* The request containing info about what to validate.
*
* @return bool
* FALSE if the response failed validation, otherwise TRUE.
*/
protected function validateResponse(Response $response, Request $request) : bool {
// Do not use Json::decode here since it coerces the response into an
// associative array, which creates validation errors.
$response_data = json_decode($response->getContent());
if (empty($response_data)) {
return TRUE;
}
$schema_ref = sprintf('file://%s/schema.json', implode('/', [
$this->appRoot,
$this->moduleHandler
->getModule('jsonapi')
->getPath(),
]));
$generic_jsonapi_schema = (object) [
'$ref' => $schema_ref,
];
return $this->validateSchema($generic_jsonapi_schema, $response_data);
}
/**
* Validates a string against a JSON Schema. It logs any possible errors.
*
* @param object $schema
* The JSON Schema object.
* @param mixed $response_data
* The JSON string to validate.
*
* @return bool
* TRUE if the string is a valid instance of the schema. FALSE otherwise.
*/
protected function validateSchema(object $schema, mixed $response_data) : bool {
// @phpstan-ignore method.deprecated
$this->validator
->check($response_data, $schema);
$is_valid = $this->validator
->isValid();
if (!$is_valid) {
$this->logger
->debug("Response failed validation.\nResponse:\n@data\n\nErrors:\n@errors", [
'@data' => Json::encode($response_data),
'@errors' => Json::encode($this->validator
->getErrors()),
]);
}
return $is_valid;
}
}
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.