diff --git a/src/Validation/RequestValidator.php b/src/Validation/RequestValidator.php index d4bba26..f874713 100644 --- a/src/Validation/RequestValidator.php +++ b/src/Validation/RequestValidator.php @@ -149,12 +149,6 @@ protected function validateParameters() protected function validateBody(): void { $expectedBody = $this->operation()->requestBody; - $actualBody = $this->request->getContent(); - - // If required, then body should be non-empty. - if ($expectedBody->required === true && empty($actualBody)) { - throw new RequestValidationException('Request body required.'); - } // Content types should match. $contentType = $this->request->header('Content-Type'); @@ -164,14 +158,20 @@ protected function validateBody(): void // Capture schemas for validation. $expectedBodyRawSchema = $expectedBody->content[$contentType]->schema; - $actualBodySchema = $actualBody; - if ($expectedBodyRawSchema->type === 'object' || $expectedBodyRawSchema->type === 'array' || $expectedBodyRawSchema->oneOf || $expectedBodyRawSchema->anyOf) { - if (in_array($contentType, ['application/json', 'application/vnd.api+json'])) { - $actualBodySchema = json_decode($actualBodySchema); - } else { - $actualBodySchema = $this->parseBodySchema(); - } + if ( + ($expectedBodyRawSchema->type === 'object' || $expectedBodyRawSchema->type === 'array' || $expectedBodyRawSchema->oneOf || $expectedBodyRawSchema->anyOf) + && in_array($contentType, ['application/json', 'application/vnd.api+json']) + ) { + $actualBodySchema = json_decode($this->request->getContent()); + } else { + $actualBodySchema = $this->parseBodySchema(); } + + // If required, then body should be non-empty. + if ($expectedBody->required === true && empty($actualBodySchema)) { + throw new RequestValidationException('Request body required!'); + } + $expectedBodySchema = $this->prepareData($expectedBodyRawSchema, 'write'); // Run validation. diff --git a/tests/Fixtures/Upload.yml b/tests/Fixtures/Upload.yml new file mode 100644 index 0000000..7c8c35e --- /dev/null +++ b/tests/Fixtures/Upload.yml @@ -0,0 +1,27 @@ +openapi: 3.0.0 +info: + title: Upload.v1 + version: '1.0' +servers: + - url: 'http://localhost:3000' +paths: + /upload: + post: + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + file: + type: string + format: binary + required: + - file + responses: + '204': + description: No Content + +components: + schemas: {} diff --git a/tests/RequestValidatorTest.php b/tests/RequestValidatorTest.php index d330073..8a3449e 100644 --- a/tests/RequestValidatorTest.php +++ b/tests/RequestValidatorTest.php @@ -565,7 +565,11 @@ public function test_handles_form_data(): void $this->post( '/users', - ['name' => 'Adam Campbell', 'email' => 'test@test.com', 'picture' => UploadedFile::fake()->image('test.jpg')], + [ + 'name' => 'Adam Campbell', + 'email' => 'test@test.com', + 'picture' => UploadedFile::fake()->image('test.jpg'), + ], ['Content-Type' => 'multipart/form-data'] ) ->assertValidRequest(); @@ -838,6 +842,18 @@ public static function enumProvider(): array ], ]; } + + public function test_validates_upload_file(): void + { + Spectator::using('Upload.yml'); + + Route::post('/upload', function () { + return response()->noContent(); + })->middleware(Middleware::class); + + $this->post('/upload', ['file' => UploadedFile::fake()->createWithContent('test.xlsx', 'Content')], ['Content-Type' => 'multipart/form-data']) + ->assertValidRequest(); + } } class TestUser extends Model