Skip to content

Commit

Permalink
Validate required missing parameters in request (#12)
Browse files Browse the repository at this point in the history
* Catch exceptions in main validation method

* Ensure missing required parameters are validated
  • Loading branch information
beblife authored Sep 5, 2022
1 parent a00e10f commit 7fa4b13
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 20 deletions.
9 changes: 9 additions & 0 deletions src/Exceptions/InvalidSchema.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ public function __construct(Validator $validator, ?Response $response = null, st
$this->status = config('schema-validation.response.status', $this->status);
}

public static function becauseMissingRequiredKeyword(string $key, string $message): self
{
return self::withMessages([
$key => [
$message,
],
]);
}

public static function becauseInvalidKeyword(string $key, string $message): self
{
return self::withMessages([
Expand Down
41 changes: 21 additions & 20 deletions src/Validators/LeagueSchemaValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
use Beblife\SchemaValidation\Exceptions\UnableToValidateSchema;
use Beblife\SchemaValidation\Schema;
use Beblife\SchemaValidation\SchemaValidator;
use cebe\openapi\exceptions\TypeErrorException;
use cebe\openapi\Reader;
use cebe\openapi\spec\Schema as SpecSchema;
use GuzzleHttp\Psr7\ServerRequest;
Expand All @@ -15,6 +14,7 @@
use League\OpenAPIValidation\PSR7\Exception\NoPath;
use League\OpenAPIValidation\PSR7\Exception\Validation\InvalidBody;
use League\OpenAPIValidation\PSR7\Exception\Validation\InvalidQueryArgs;
use League\OpenAPIValidation\PSR7\Exception\Validation\RequiredParameterMissing;
use League\OpenAPIValidation\PSR7\ServerRequestValidator;
use League\OpenAPIValidation\PSR7\ValidatorBuilder;
use League\OpenAPIValidation\Schema\Exception\KeywordMismatch;
Expand Down Expand Up @@ -43,6 +43,9 @@ public function __construct(string $specPath)
}
}

/**
* @throws InvalidSchema
*/
public function validate(Request $request, ?Schema $schema = null): Request
{
try {
Expand All @@ -55,39 +58,35 @@ public function validate(Request $request, ?Schema $schema = null): Request
}
} catch(NoPath $exception) {
throw UnableToValidateSchema::becauseNoSchemaForRequest($request);
} catch(InvalidQueryArgs $exception) {
if($exception->getPrevious() instanceof RequiredParameterMissing) {
throw InvalidSchema::becauseMissingRequiredKeyword(
$exception->getPrevious()->name(),
"Field '{$exception->getPrevious()->name()}' is required.",
);
}

throw $this->validationException($exception->getPrevious()->getPrevious());
} catch(InvalidBody $exception) {
throw $this->validationException($exception->getPrevious());
} catch (KeywordMismatch $keywordMismatch) {
throw $this->validationException($keywordMismatch);
}

return $request;
}

/**
* @throws InvalidSchema
*/
protected function validateFromSpec(Request $request): void
{
try {
$this->validator->validate($this->toServerRequest($request));
} catch(InvalidQueryArgs $exeception) {
throw $this->validationException($exeception->getPrevious()->getPrevious());
} catch(InvalidBody $exception) {
throw $this->validationException($exception->getPrevious());
}
$this->validator->validate($this->toServerRequest($request));
}

/**
* @throws InvalidSchema
* @throws TypeErrorException
*/
protected function validateForSchema(Request $request, Schema $schema): void
{
$validator = new LeagueValidator(LeagueValidator::VALIDATE_AS_REQUEST);
$specSchema = Reader::readFromJson(json_encode($schema->toArray()), SpecSchema::class);

try {
$validator->validate($request->all(), $specSchema);
} catch (KeywordMismatch $keywordMismatch) {
throw $this->validationException($keywordMismatch);
}
$validator->validate($request->all(), $specSchema);
}

protected function toServerRequest(Request $request): ServerRequestInterface
Expand Down Expand Up @@ -139,6 +138,8 @@ protected function messageForInvalidKeyword(KeywordMismatch $keywordMismatch): s
'Size of an array' => 'Size',
'All array' => 'All',
"The number of object's" => 'Object',
'Required property ' => 'Field ',
' must be present in the object' => ' is required',
] as $search => $replace) {
$message = str_replace($search, $replace, $message);
}
Expand Down
32 changes: 32 additions & 0 deletions tests/LeagueSchemaValidatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,38 @@ public function test_it_can_validate_the_body_on_a_request(string $param, $value
$this->fail('A validation exception was not thrown for parameter: '. $param);
}

public function test_it_validates_required_missing_query_parameters(): void
{
$validator = new LeagueSchemaValidator($this->specFixture('validation.v30.json'));
$request = $this->createRequest('GET', '/missing-parameters');

try {
$validator->validate($request);
} catch(InvalidSchema $exception) {
$this->assertFormattedValidationException($exception, 'missing', "Field 'missing' is required.");

return;
}

$this->fail('A validation exception was not thrown for a missing query parameter');
}

public function test_it_validates_required_missing_body_parameters(): void
{
$validator = new LeagueSchemaValidator($this->specFixture('validation.v30.json'));
$request = $this->createRequest('POST', '/missing-parameters');

try {
$validator->validate($request);
} catch(InvalidSchema $exception) {
$this->assertFormattedValidationException($exception, 'missing', "Field 'missing' is required.");

return;
}

$this->fail('A validation exception was not thrown for a missing body parameter');
}

public function invalidData(): array
{
return [
Expand Down
33 changes: 33 additions & 0 deletions tests/__fixtures__/specs/validation.v30.json
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,39 @@
}
}
}
},
"/missing-parameters": {
"get": {
"parameters": [
{
"in": "query",
"name": "missing",
"required": true,
"schema": {
"type": "boolean"
}
}
]
},
"post": {
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"missing": {
"type": "boolean"
}
},
"required": [
"missing"
]
}
}
}
}
}
}
}
}

0 comments on commit 7fa4b13

Please sign in to comment.