From d2ac7a5bad1a7a7efc4374c1f2ba3d951a488297 Mon Sep 17 00:00:00 2001 From: Patrick-ChStudio <128053746+Patrick-ChStudio@users.noreply.github.com> Date: Thu, 16 Mar 2023 16:16:54 +0100 Subject: [PATCH] Update Factory.php Raven is really cool. It that might happen that, when an api evolves, some deprecated infos remain in its response. What is really top on XML is the XSD, which checks the structure of the data. Json des not have something like XSD. From openApi we can extract a structure definition. Why not using it to check an api response object's structure? This is basically the goal of those changes, allowing the reference structure tree to be used externally. It could be further used to check json response structure conformity. Not talking about values here, but properties being present or not, tested or ignored. --- .../LeagueOpenAPIValidation/Factory.php | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/Bridge/LeagueOpenAPIValidation/Factory.php b/src/Bridge/LeagueOpenAPIValidation/Factory.php index 3217888..90ab395 100644 --- a/src/Bridge/LeagueOpenAPIValidation/Factory.php +++ b/src/Bridge/LeagueOpenAPIValidation/Factory.php @@ -62,4 +62,59 @@ public function getResponseValidator(): ResponseValidator throw new InvalidOpenApiDefinitionException($error); } } + + /** + * OpenApi doc is internally transposed by Raven to a tree of infos. + * This method gives the opportinity to retreive a subtree, based on the "path" in the api doc + * that is represented by the tupple: http method / uri / status code / content type + * One usage can be to further process the resulting array + * in order to check an api json response object's structure conformity + */ + public function getReferenceStructure(string $method, string $uri, int $statusCode, ?string $contentType): ?array + { + $decoded = json_decode(json_encode( + $this->validator->getResponseValidator()->getSchema()->getSerializableData() + ), true); + // Looking for paths with care of parameters not necessarily named the same in both yaml files (test def & openApi) + $workedUri = $this->cleanPath($uri); + foreach ($decoded['paths'] as $path => $data) { + if ($path === $uri || $this->cleanPath($path) === $workedUri) { + // Path to access data in multiple levels nested object + $pathSegments = $this->buildPathSegments($method, $statusCode, $contentType); + $roadTraveled = ''; + foreach ($pathSegments as $segment) { + $roadTraveled .= '/'.$segment; + if (!isset($data[$segment])) { + throw new InvalidArgumentException(sprintf( + 'The following path was not found in object definition from openApi: %s', + $roadTraveled + )); + } + $data = $data[$segment]; + } + + return $data; + } + } + + return null; + } + + private function cleanPath(string $path): string + { + // Replace parameter by a star and remove query string + return preg_replace(['/\{[^\}]+\}/', '/\?.+/'], ['*', ''], $path); + } + + private function buildPathSegments(string $method, int $statusCode, ?string $contentType): array + { + $return = [strtolower($method), 'responses', $statusCode, 'content']; + if ($contentType !== null) { + $return[] = strtolower($contentType); + } + $return[] = 'schema'; + $return[] = 'properties'; + + return $return; + } }