Skip to content

Commit 5633546

Browse files
authored
Merge pull request #6 from carsdotcom/valiate-string-json
feat: Add a clear method to validate encoded JSON strings
2 parents 95e0e09 + 164143b commit 5633546

File tree

3 files changed

+56
-2
lines changed

3 files changed

+56
-2
lines changed

app/SchemaValidator.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@
1616
* @method static array|object getSchemaContents(string $relativeUri, bool $associative = true)
1717
* @method static void putSchemaContents(string $relativeUri, array|object $schema)
1818
* @method static string registerRawSchema(bool|object|string $schema)
19-
* @method static bool validate(array|object $data, string $schema)
20-
* @method static bool validateOrThrow(string|array|object $data, string $schema, string $exceptionMessage = null, bool $appendValidationDescriptions = false, int $failureHttpStatusCode = Response::HTTP_BAD_REQUEST)
19+
* @method static bool validate(mixed $data, string $schema)
20+
* @method static bool validateOrThrow(mixed $data, string $schema, string $exceptionMessage = null, bool $appendValidationDescriptions = false, int $failureHttpStatusCode = Response::HTTP_BAD_REQUEST)
21+
* @method static bool validateEncodedStringOrThrow(mixed $data, string $schema, string $exceptionMessage = null, bool $appendValidationDescriptions = false, int $failureHttpStatusCode = Response::HTTP_BAD_REQUEST)
2122
*/
2223
class SchemaValidator extends Facade
2324
{

app/SchemaValidatorService.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,24 @@ public function validateOrThrow(
138138
return true;
139139
}
140140

141+
/**
142+
* This method will attempt to validate the provided JSON-encoded string against the provided schema.
143+
*/
144+
public function validateEncodedStringOrThrow(
145+
string $data,
146+
$schema,
147+
string $exceptionMessage = null,
148+
bool $appendValidationDescriptions = false,
149+
int $failureHttpStatusCode = Response::HTTP_BAD_REQUEST,
150+
): bool
151+
{
152+
// Using the non-associative decode is both how Opis documents it
153+
// https://opis.io/json-schema/2.x/quick-start.html
154+
// and is known to avoid `{}` vs `[]` confusion
155+
$decodedData = json_decode($data, associative: false, flags: JSON_THROW_ON_ERROR);
156+
return $this->validateOrThrow($decodedData, $schema, $exceptionMessage, $appendValidationDescriptions, $failureHttpStatusCode);
157+
}
158+
141159
/**
142160
* Given anything that Opis can use as a schema (object, boolean, json-encoded string)
143161
* register the schema into our namespace, so it can safely contain relative links of its own.

tests/Feature/SchemaValidatorServiceTest.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
namespace Tests\Feature;
88

9+
use Carsdotcom\JsonSchemaValidation\Exceptions\JsonSchemaValidationException;
910
use Carsdotcom\JsonSchemaValidation\SchemaValidatorService;
1011
use Illuminate\Support\Facades\Config;
1112
use Opis\JsonSchema\Exceptions\UnresolvedReferenceException;
@@ -87,4 +88,38 @@ public function testRegisterRawSchema(): void
8788
self::assertStringStartsWith(Config::get('json-schema.base_url'), $absoluteRaw);
8889
self::assertTrue($validator->validate($vins, $absoluteRaw));
8990
}
91+
92+
/**
93+
* @dataProvider provideValidateEncodedStringOrThrow
94+
*/
95+
public function testValidateEncodedStringOrThrow(string $encodedData, mixed $schema, bool $expectedSuccess): void
96+
{
97+
$validator = new SchemaValidatorService();
98+
99+
try {
100+
self::assertTrue($validator->validateEncodedStringOrThrow($encodedData, $schema));
101+
if (!$expectedSuccess) {
102+
self::fail("Should have thrown JsonSchemaValidationException");
103+
}
104+
} catch (JsonSchemaValidationException $e) {
105+
if ($expectedSuccess) {
106+
self::assertTrue(false, "Expected success, instead got " . $e->errorsAsMultilineString());
107+
} else {
108+
self::addToAssertionCount(1);
109+
}
110+
}
111+
}
112+
113+
public function provideValidateEncodedStringOrThrow(): array
114+
{
115+
return [
116+
'primitive, string schema' => ['420', '{"type": "number", "minimum": 69}', true],
117+
'primitive, string schema fails' => ['42', '{"type": "number", "minimum": 69}', false],
118+
'empty object is still an object' => ['{}', '{"type": "object"}', true],
119+
'empty object is not an array' => ['{}', '{"type": "array"}', false],
120+
'typical complex object, success' => ['{"a":1}', '{"type":"object","properties":{"a":{"type":"number"}}, "required":["a"]}', true],
121+
'typical complex object, failure' => ['{"b":1}', '{"type":"object","properties":{"a":{"type":"number"}}, "required":["a"]}', false],
122+
];
123+
}
124+
90125
}

0 commit comments

Comments
 (0)