Skip to content

Commit 4cf29fb

Browse files
Merge pull request #110 from RonasIT/dpankratov/disable-main-doc-validation-in-constructor
Dpankratov/disable main doc validation in constructor
2 parents 1ce8737 + 80b9853 commit 4cf29fb

File tree

7 files changed

+351
-51
lines changed

7 files changed

+351
-51
lines changed

src/Services/SwaggerService.php

Lines changed: 52 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class SwaggerService
3131
public const SWAGGER_VERSION = '2.0';
3232

3333
protected $driver;
34+
protected $openAPIValidator;
3435

3536
protected $data;
3637
protected $config;
@@ -57,6 +58,8 @@ class SwaggerService
5758

5859
public function __construct(Container $container)
5960
{
61+
$this->openAPIValidator = app(SwaggerSpecValidator::class);
62+
6063
$this->initConfig();
6164

6265
$this->setDriver();
@@ -68,9 +71,7 @@ public function __construct(Container $container)
6871

6972
$this->data = $this->driver->getTmpData();
7073

71-
if (!empty($this->data)) {
72-
$this->validateSpec($this->data);
73-
} else {
74+
if (empty($this->data)) {
7475
$this->data = $this->generateEmptyData();
7576

7677
$this->driver->saveTmpData($this->data);
@@ -692,55 +693,20 @@ public function getDocFileContent()
692693
{
693694
$documentation = $this->driver->getDocumentation();
694695

696+
$this->openAPIValidator->validate($documentation);
697+
695698
$additionalDocs = config('auto-doc.additional_paths', []);
696699

697700
foreach ($additionalDocs as $filePath) {
698-
$fullFilePath = base_path($filePath);
699-
700701
try {
701-
if (!file_exists($fullFilePath)) {
702-
throw new DocFileNotExistsException($fullFilePath);
703-
}
704-
705-
$fileContent = json_decode(file_get_contents($fullFilePath), true);
706-
707-
if (empty($fileContent)) {
708-
throw new EmptyDocFileException($fullFilePath);
709-
}
710-
711-
$this->validateSpec($fileContent);
702+
$additionalDocContent = $this->getOpenAPIFileContent(base_path($filePath));
712703
} catch (DocFileNotExistsException|EmptyDocFileException|InvalidSwaggerSpecException $exception) {
713704
report($exception);
714705

715706
continue;
716707
}
717708

718-
$paths = array_keys($fileContent['paths']);
719-
720-
foreach ($paths as $path) {
721-
$additionalDocPath = $fileContent['paths'][$path];
722-
723-
if (empty($documentation['paths'][$path])) {
724-
$documentation['paths'][$path] = $additionalDocPath;
725-
} else {
726-
$methods = array_keys($documentation['paths'][$path]);
727-
$additionalDocMethods = array_keys($additionalDocPath);
728-
729-
foreach ($additionalDocMethods as $method) {
730-
if (!in_array($method, $methods)) {
731-
$documentation['paths'][$path][$method] = $additionalDocPath[$method];
732-
}
733-
}
734-
}
735-
}
736-
737-
$definitions = array_keys($fileContent['definitions']);
738-
739-
foreach ($definitions as $definition) {
740-
if (empty($documentation['definitions'][$definition])) {
741-
$documentation['definitions'][$definition] = $fileContent['definitions'][$definition];
742-
}
743-
}
709+
$this->mergeOpenAPIDocs($documentation, $additionalDocContent);
744710
}
745711

746712
return $documentation;
@@ -871,8 +837,50 @@ protected function prepareInfo(array $info): array
871837
return $info;
872838
}
873839

874-
protected function validateSpec(array $doc): void
840+
protected function getOpenAPIFileContent(string $filePath): array
841+
{
842+
if (!file_exists($filePath)) {
843+
throw new DocFileNotExistsException($filePath);
844+
}
845+
846+
$fileContent = json_decode(file_get_contents($filePath), true);
847+
848+
if (empty($fileContent)) {
849+
throw new EmptyDocFileException($filePath);
850+
}
851+
852+
$this->openAPIValidator->validate($fileContent);
853+
854+
return $fileContent;
855+
}
856+
857+
protected function mergeOpenAPIDocs(array &$documentation, array $additionalDocumentation): void
875858
{
876-
app(SwaggerSpecValidator::class)->validate($doc);
859+
$paths = array_keys($additionalDocumentation['paths']);
860+
861+
foreach ($paths as $path) {
862+
$additionalDocPath = $additionalDocumentation['paths'][$path];
863+
864+
if (empty($documentation['paths'][$path])) {
865+
$documentation['paths'][$path] = $additionalDocPath;
866+
} else {
867+
$methods = array_keys($documentation['paths'][$path]);
868+
$additionalDocMethods = array_keys($additionalDocPath);
869+
870+
foreach ($additionalDocMethods as $method) {
871+
if (!in_array($method, $methods)) {
872+
$documentation['paths'][$path][$method] = $additionalDocPath[$method];
873+
}
874+
}
875+
}
876+
}
877+
878+
$definitions = array_keys($additionalDocumentation['definitions']);
879+
880+
foreach ($definitions as $definition) {
881+
if (empty($documentation['definitions'][$definition])) {
882+
$documentation['definitions'][$definition] = $additionalDocumentation['definitions'][$definition];
883+
}
884+
}
877885
}
878886
}

src/Validators/SwaggerSpecValidator.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,9 @@ protected function validateSecurityDefinitions(): void
155155

156156
$this->validateFieldsPresent(self::REQUIRED_FIELDS['security_definition'], $parentId);
157157

158-
$this->validateFieldValue("{$parentId}.'type", self::ALLOWED_VALUES['security_definition_type']);
159-
$this->validateFieldValue("{$parentId}.'in", self::ALLOWED_VALUES['security_definition_in']);
160-
$this->validateFieldValue("{$parentId}.'flow", self::ALLOWED_VALUES['security_definition_flow']);
158+
$this->validateFieldValue("{$parentId}.type", self::ALLOWED_VALUES['security_definition_type']);
159+
$this->validateFieldValue("{$parentId}.in", self::ALLOWED_VALUES['security_definition_in']);
160+
$this->validateFieldValue("{$parentId}.flow", self::ALLOWED_VALUES['security_definition_flow']);
161161
}
162162
}
163163

tests/SwaggerServiceTest.php

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -271,23 +271,39 @@ public function getConstructorInvalidTmpData(): array
271271
'exceptionMessage' => "Validation failed. Path parameters cannot be optional. "
272272
. "Set required=true for the 'username' parameters at operation 'paths./users.get'."
273273
],
274+
[
275+
'tmpDoc' => 'documentation/invalid_format__security_definition__type',
276+
'exception' => InvalidSwaggerSpecException::class,
277+
'exceptionMessage' => "Validation failed. Field 'securityDefinitions.0.type' has an invalid value: invalid. Allowed values: basic, apiKey, oauth2."
278+
],
279+
[
280+
'tmpDoc' => 'documentation/invalid_format__security_definition__flow',
281+
'exception' => InvalidSwaggerSpecException::class,
282+
'exceptionMessage' => "Validation failed. Field 'securityDefinitions.0.flow' has an invalid value: invalid. Allowed values: implicit, password, application, accessCode."
283+
],
284+
[
285+
'tmpDoc' => 'documentation/invalid_format__security_definition__in',
286+
'exception' => InvalidSwaggerSpecException::class,
287+
'exceptionMessage' => "Validation failed. Field 'securityDefinitions.0.in' has an invalid value: invalid. Allowed values: query, header."
288+
],
274289
];
275290
}
276291

277292
/**
278293
* @dataProvider getConstructorInvalidTmpData
279294
*
280-
* @param string $tmpDoc
295+
* @param string $docFilePath
281296
* @param string $exception
282297
* @param string $exceptionMessage
283298
*/
284-
public function testConstructorInvalidTmpData(string $tmpDoc, string $exception, string $exceptionMessage)
299+
public function testGetDocFileContentInvalidTmpData(string $docFilePath, string $exception, string $exceptionMessage)
285300
{
286-
$this->mockDriverGetTpmData($this->getJsonFixture($tmpDoc));
301+
$this->mockDriverGetDocumentation($this->getJsonFixture($docFilePath));
302+
287303
$this->expectException($exception);
288304
$this->expectExceptionMessage($exceptionMessage);
289305

290-
app(SwaggerService::class);
306+
app(SwaggerService::class)->getDocFileContent();
291307
}
292308

293309
public function testEmptyContactEmail()
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
{
2+
"swagger": "2.0",
3+
"host": "localhost",
4+
"basePath": "\/",
5+
"schemes": [],
6+
"paths": {
7+
"\/api\/users":
8+
{
9+
"post":
10+
{
11+
"tags": ["api"],
12+
"consumes": ["application\/x-www-form-urlencoded"],
13+
"produces": ["application\/json"],
14+
"parameters": [
15+
{
16+
"in": "body",
17+
"name": "body",
18+
"description": "",
19+
"required": true,
20+
"schema": {
21+
"$ref": "#/definitions/apiusersObject"
22+
}
23+
}
24+
],
25+
"responses":
26+
{
27+
"403":
28+
{
29+
"description": "Forbidden",
30+
"schema":
31+
{
32+
"example":
33+
{
34+
"message": "This action is unauthorized."
35+
}
36+
}
37+
}
38+
},
39+
"security": [],
40+
"description": "",
41+
"summary": "test"
42+
}
43+
}
44+
},
45+
"definitions": {
46+
"apiusersObject": {
47+
"type": "object",
48+
"properties": {
49+
"query": {
50+
"type": "string",
51+
"description": ""
52+
},
53+
"user_id": {
54+
"type": "integer",
55+
"description": "with_to_array_rule_string_name"
56+
},
57+
"is_email_enabled": {
58+
"type": "string",
59+
"description": "test_rule_without_to_string"
60+
}
61+
},
62+
"required": {
63+
"0": "query"
64+
},
65+
"example": {
66+
"first_name": "andrey",
67+
"last_name": "voronin"
68+
}
69+
}
70+
},
71+
"info": {
72+
"description": "This is automatically collected documentation",
73+
"version": "0.0.0",
74+
"title": "Name of Your Application",
75+
"termsOfService": "",
76+
"contact":
77+
{
78+
"email": "your@email.com"
79+
}
80+
},
81+
"securityDefinitions": [
82+
{
83+
"type": "basic",
84+
"in": "query",
85+
"flow": "invalid"
86+
}
87+
]
88+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
{
2+
"swagger": "2.0",
3+
"host": "localhost",
4+
"basePath": "\/",
5+
"schemes": [],
6+
"paths": {
7+
"\/api\/users":
8+
{
9+
"post":
10+
{
11+
"tags": ["api"],
12+
"consumes": ["application\/x-www-form-urlencoded"],
13+
"produces": ["application\/json"],
14+
"parameters": [
15+
{
16+
"in": "body",
17+
"name": "body",
18+
"description": "",
19+
"required": true,
20+
"schema": {
21+
"$ref": "#/definitions/apiusersObject"
22+
}
23+
}
24+
],
25+
"responses":
26+
{
27+
"403":
28+
{
29+
"description": "Forbidden",
30+
"schema":
31+
{
32+
"example":
33+
{
34+
"message": "This action is unauthorized."
35+
}
36+
}
37+
}
38+
},
39+
"security": [],
40+
"description": "",
41+
"summary": "test"
42+
}
43+
}
44+
},
45+
"definitions": {
46+
"apiusersObject": {
47+
"type": "object",
48+
"properties": {
49+
"query": {
50+
"type": "string",
51+
"description": ""
52+
},
53+
"user_id": {
54+
"type": "integer",
55+
"description": "with_to_array_rule_string_name"
56+
},
57+
"is_email_enabled": {
58+
"type": "string",
59+
"description": "test_rule_without_to_string"
60+
}
61+
},
62+
"required": {
63+
"0": "query"
64+
},
65+
"example": {
66+
"first_name": "andrey",
67+
"last_name": "voronin"
68+
}
69+
}
70+
},
71+
"info": {
72+
"description": "This is automatically collected documentation",
73+
"version": "0.0.0",
74+
"title": "Name of Your Application",
75+
"termsOfService": "",
76+
"contact":
77+
{
78+
"email": "your@email.com"
79+
}
80+
},
81+
"securityDefinitions": [
82+
{
83+
"type": "basic",
84+
"in": "invalid",
85+
"flow": "password"
86+
}
87+
]
88+
}

0 commit comments

Comments
 (0)