Skip to content

Commit

Permalink
feat: Add a clear method to validate encoded JSON strings
Browse files Browse the repository at this point in the history
  • Loading branch information
jwadhams committed Nov 12, 2024
1 parent 95e0e09 commit 164143b
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 2 deletions.
5 changes: 3 additions & 2 deletions app/SchemaValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@
* @method static array|object getSchemaContents(string $relativeUri, bool $associative = true)
* @method static void putSchemaContents(string $relativeUri, array|object $schema)
* @method static string registerRawSchema(bool|object|string $schema)
* @method static bool validate(array|object $data, string $schema)
* @method static bool validateOrThrow(string|array|object $data, string $schema, string $exceptionMessage = null, bool $appendValidationDescriptions = false, int $failureHttpStatusCode = Response::HTTP_BAD_REQUEST)
* @method static bool validate(mixed $data, string $schema)
* @method static bool validateOrThrow(mixed $data, string $schema, string $exceptionMessage = null, bool $appendValidationDescriptions = false, int $failureHttpStatusCode = Response::HTTP_BAD_REQUEST)
* @method static bool validateEncodedStringOrThrow(mixed $data, string $schema, string $exceptionMessage = null, bool $appendValidationDescriptions = false, int $failureHttpStatusCode = Response::HTTP_BAD_REQUEST)
*/
class SchemaValidator extends Facade
{
Expand Down
18 changes: 18 additions & 0 deletions app/SchemaValidatorService.php
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,24 @@ public function validateOrThrow(
return true;
}

/**
* This method will attempt to validate the provided JSON-encoded string against the provided schema.
*/
public function validateEncodedStringOrThrow(
string $data,
$schema,
string $exceptionMessage = null,
bool $appendValidationDescriptions = false,
int $failureHttpStatusCode = Response::HTTP_BAD_REQUEST,
): bool
{
// Using the non-associative decode is both how Opis documents it
// https://opis.io/json-schema/2.x/quick-start.html
// and is known to avoid `{}` vs `[]` confusion
$decodedData = json_decode($data, associative: false, flags: JSON_THROW_ON_ERROR);
return $this->validateOrThrow($decodedData, $schema, $exceptionMessage, $appendValidationDescriptions, $failureHttpStatusCode);
}

/**
* Given anything that Opis can use as a schema (object, boolean, json-encoded string)
* register the schema into our namespace, so it can safely contain relative links of its own.
Expand Down
35 changes: 35 additions & 0 deletions tests/Feature/SchemaValidatorServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

namespace Tests\Feature;

use Carsdotcom\JsonSchemaValidation\Exceptions\JsonSchemaValidationException;
use Carsdotcom\JsonSchemaValidation\SchemaValidatorService;
use Illuminate\Support\Facades\Config;
use Opis\JsonSchema\Exceptions\UnresolvedReferenceException;
Expand Down Expand Up @@ -87,4 +88,38 @@ public function testRegisterRawSchema(): void
self::assertStringStartsWith(Config::get('json-schema.base_url'), $absoluteRaw);
self::assertTrue($validator->validate($vins, $absoluteRaw));
}

/**
* @dataProvider provideValidateEncodedStringOrThrow
*/
public function testValidateEncodedStringOrThrow(string $encodedData, mixed $schema, bool $expectedSuccess): void
{
$validator = new SchemaValidatorService();

try {
self::assertTrue($validator->validateEncodedStringOrThrow($encodedData, $schema));
if (!$expectedSuccess) {
self::fail("Should have thrown JsonSchemaValidationException");
}
} catch (JsonSchemaValidationException $e) {
if ($expectedSuccess) {
self::assertTrue(false, "Expected success, instead got " . $e->errorsAsMultilineString());
} else {
self::addToAssertionCount(1);
}
}
}

public function provideValidateEncodedStringOrThrow(): array
{
return [
'primitive, string schema' => ['420', '{"type": "number", "minimum": 69}', true],
'primitive, string schema fails' => ['42', '{"type": "number", "minimum": 69}', false],
'empty object is still an object' => ['{}', '{"type": "object"}', true],
'empty object is not an array' => ['{}', '{"type": "array"}', false],
'typical complex object, success' => ['{"a":1}', '{"type":"object","properties":{"a":{"type":"number"}}, "required":["a"]}', true],
'typical complex object, failure' => ['{"b":1}', '{"type":"object","properties":{"a":{"type":"number"}}, "required":["a"]}', false],
];
}

}

0 comments on commit 164143b

Please sign in to comment.