Skip to content

Commit e939c8f

Browse files
authored
Merge pull request #116 from RonasIT/96-add-response-schemes
feat: add response schemas.
2 parents 4437b15 + ddcc184 commit e939c8f

19 files changed

+384
-33
lines changed

src/Http/Middleware/AutoDocMiddleware.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public function handle($request, Closure $next)
1616
{
1717
$response = $next($request);
1818

19-
if ((config('app.env') == 'testing') && !self::$skipped && !empty($request->route())) {
19+
if ((config('app.env') === 'testing') && !self::$skipped && !empty($request->route())) {
2020
app(SwaggerService::class)->addData($request, $response);
2121
}
2222

src/Services/SwaggerService.php

Lines changed: 68 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public function __construct(Container $container)
6969

7070
$this->setDriver();
7171

72-
if (config('app.env') == 'testing') {
72+
if (config('app.env') === 'testing') {
7373
$this->container = $container;
7474

7575
$this->security = $this->config['security'];
@@ -281,6 +281,60 @@ protected function markAsDeprecated(array $annotations)
281281
$this->item['deprecated'] = Arr::get($annotations, 'deprecated', false);
282282
}
283283

284+
protected function saveResponseSchema(?array $content, string $definition): void
285+
{
286+
if (empty($content)) {
287+
return;
288+
}
289+
290+
$schemaProperties = [];
291+
$schemaType = 'object';
292+
293+
if (array_is_list($content)) {
294+
$this->saveListResponseDefinitions($content, $schemaProperties);
295+
296+
$schemaType = 'array';
297+
} else {
298+
$this->saveObjectResponseDefinitions($content, $schemaProperties, $definition);
299+
}
300+
301+
$this->data['definitions'][$definition] = [
302+
'type' => $schemaType,
303+
'properties' => $schemaProperties
304+
];
305+
}
306+
307+
protected function saveListResponseDefinitions(array $content, array &$schemaProperties): void
308+
{
309+
$types = [];
310+
311+
foreach ($content as $value) {
312+
$type = gettype($value);
313+
314+
if (!in_array($type, $types)) {
315+
$types[] = $type;
316+
$schemaProperties['items']['allOf'][]['type'] = $type;
317+
}
318+
}
319+
}
320+
321+
protected function saveObjectResponseDefinitions(array $content, array &$schemaProperties, string $definition): void
322+
{
323+
$properties = Arr::get($this->data['definitions'], $definition, []);
324+
325+
foreach ($content as $name => $value) {
326+
$property = Arr::get($properties, $name, []);
327+
328+
if (is_null($value)) {
329+
$property['nullable'] = true;
330+
} else {
331+
$property['type'] = gettype($value);
332+
}
333+
334+
$schemaProperties[$name] = $property;
335+
}
336+
}
337+
284338
protected function parseResponse($response)
285339
{
286340
$produceList = $this->data['paths'][$this->uri][$this->method]['produces'];
@@ -325,6 +379,15 @@ protected function parseResponse($response)
325379
$produce
326380
);
327381
}
382+
383+
$action = Str::ucfirst($this->getActionName($this->uri));
384+
$definition = "{$this->method}{$action}{$code}ResponseObject";
385+
386+
$this->saveResponseSchema($content, $definition);
387+
388+
if (is_array($this->item['responses'][$code])) {
389+
$this->item['responses'][$code]['schema']['$ref'] = "#/definitions/{$definition}";
390+
}
328391
}
329392

330393
protected function saveExample($code, $content, $produce)
@@ -424,7 +487,7 @@ protected function saveGetRequestParameters($rules, array $attributes, array $an
424487
}
425488

426489
$existedParameter = Arr::first($this->item['parameters'], function ($existedParameter) use ($parameter) {
427-
return $existedParameter['name'] == $parameter;
490+
return $existedParameter['name'] === $parameter;
428491
});
429492

430493
if (empty($existedParameter)) {
@@ -542,7 +605,7 @@ protected function requestHasBody(): bool
542605
$parameters = $this->data['paths'][$this->uri][$this->method]['parameters'];
543606

544607
$bodyParamExisted = Arr::where($parameters, function ($value) {
545-
return $value['name'] == 'body';
608+
return $value['name'] === 'body';
546609
});
547610

548611
return empty($bodyParamExisted);
@@ -552,7 +615,7 @@ public function getConcreteRequest()
552615
{
553616
$controller = $this->request->route()->getActionName();
554617

555-
if ($controller == 'Closure') {
618+
if ($controller === 'Closure') {
556619
return null;
557620
}
558621

@@ -735,7 +798,7 @@ protected function camelCaseToUnderScore($input): string
735798
$ret = $matches[0];
736799

737800
foreach ($ret as &$match) {
738-
$match = $match == strtoupper($match) ? strtolower($match) : lcfirst($match);
801+
$match = ($match === strtoupper($match)) ? strtolower($match) : lcfirst($match);
739802
}
740803

741804
return implode('_', $ret);

tests/fixtures/AutoDocMiddlewareTest/tmp_data_search_roles_request.json

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@
6565
}
6666
]
6767
}
68-
]
68+
],
69+
"$ref": "#/definitions/getUsersroles200ResponseObject"
6970
}
7071
}
7172
},
@@ -76,7 +77,20 @@
7677
}
7778
}
7879
},
79-
"definitions": {},
80+
"definitions": {
81+
"getUsersroles200ResponseObject": {
82+
"type": "array",
83+
"properties": {
84+
"items": {
85+
"allOf": [
86+
{
87+
"type": "array"
88+
}
89+
]
90+
}
91+
}
92+
}
93+
},
8094
"info": {
8195
"description": "This is automatically collected documentation",
8296
"version": "0.0.0",

tests/fixtures/SwaggerServiceTest/tmp_data_create_user_request.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
"description": "Forbidden",
3131
"schema":
3232
{
33+
"$ref": "#/definitions/postApiusers403ResponseObject",
3334
"example":
3435
{
3536
"message": "This action is unauthorized."
@@ -68,6 +69,14 @@
6869
"first_name": "andrey",
6970
"last_name": "voronin"
7071
}
72+
},
73+
"postApiusers403ResponseObject": {
74+
"type": "object",
75+
"properties": {
76+
"message": {
77+
"type": "string"
78+
}
79+
}
7180
}
7281
},
7382
"info":

tests/fixtures/SwaggerServiceTest/tmp_data_get_user_request.json

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@
6060
"id": 2,
6161
"name": "client"
6262
}
63-
}
63+
},
64+
"$ref": "#/definitions/getUsers{id}assignRole{roleId}200ResponseObject"
6465
}
6566
}
6667
},
@@ -71,7 +72,25 @@
7172
}
7273
}
7374
},
74-
"definitions": {},
75+
"definitions": {
76+
"getUsers{id}assignRole{roleId}200ResponseObject": {
77+
"type": "object",
78+
"properties": {
79+
"id": {
80+
"type": "integer"
81+
},
82+
"name": {
83+
"type": "string"
84+
},
85+
"likes_count": {
86+
"type": "integer"
87+
},
88+
"role": {
89+
"type": "array"
90+
}
91+
}
92+
}
93+
},
7594
"info": {
7695
"description": "This is automatically collected documentation",
7796
"version": "0.0.0",

tests/fixtures/SwaggerServiceTest/tmp_data_post_user_request.json

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@
5555
}
5656
]
5757
}
58-
]
58+
],
59+
"$ref": "#/definitions/postUsers200ResponseObject"
5960
}
6061
}
6162
},
@@ -97,6 +98,18 @@
9798
"required": [
9899
"query"
99100
]
101+
},
102+
"postUsers200ResponseObject": {
103+
"type": "array",
104+
"properties": {
105+
"items": {
106+
"allOf": [
107+
{
108+
"type": "array"
109+
}
110+
]
111+
}
112+
}
100113
}
101114
},
102115
"info": {

tests/fixtures/SwaggerServiceTest/tmp_data_post_user_request_with_object_params.json

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@
5353
}
5454
]
5555
}
56-
]
56+
],
57+
"$ref": "#/definitions/postUsers200ResponseObject"
5758
}
5859
}
5960
},
@@ -93,6 +94,18 @@
9394
"notification_settings": "RonasIT\\Support\\Tests\\Support\\Mock\\TestNotificationSetting"
9495
},
9596
"required": ["query"]
97+
},
98+
"postUsers200ResponseObject": {
99+
"type": "array",
100+
"properties": {
101+
"items": {
102+
"allOf": [
103+
{
104+
"type": "array"
105+
}
106+
]
107+
}
108+
}
96109
}
97110
},
98111
"info": {

tests/fixtures/SwaggerServiceTest/tmp_data_put_user_request_with_early_generated_doc.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,8 @@
103103
"204": {
104104
"description": "Operation successfully done",
105105
"schema": {
106-
"example": null
106+
"example": null,
107+
"$ref": "#/definitions/patchUsers{id}204ResponseObject"
107108
}
108109
}
109110
},

tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_closure_request.json

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@
4343
}
4444
]
4545
}
46-
]
46+
],
47+
"$ref": "#/definitions/getUsersroles200ResponseObject"
4748
}
4849
}
4950
},
@@ -52,7 +53,20 @@
5253
}
5354
}
5455
},
55-
"definitions": {},
56+
"definitions": {
57+
"getUsersroles200ResponseObject": {
58+
"type": "array",
59+
"properties": {
60+
"items": {
61+
"allOf": [
62+
{
63+
"type": "array"
64+
}
65+
]
66+
}
67+
}
68+
}
69+
},
5670
"info": {
5771
"description": "This is automatically collected documentation",
5872
"version": "0.0.0",

tests/fixtures/SwaggerServiceTest/tmp_data_search_roles_request.json

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@
6565
}
6666
]
6767
}
68-
]
68+
],
69+
"$ref": "#/definitions/getUsersroles200ResponseObject"
6970
}
7071
}
7172
},
@@ -76,7 +77,20 @@
7677
}
7778
}
7879
},
79-
"definitions": {},
80+
"definitions": {
81+
"getUsersroles200ResponseObject": {
82+
"type": "array",
83+
"properties": {
84+
"items": {
85+
"allOf": [
86+
{
87+
"type": "array"
88+
}
89+
]
90+
}
91+
}
92+
}
93+
},
8094
"info": {
8195
"description": "This is automatically collected documentation",
8296
"version": "0.0.0",

0 commit comments

Comments
 (0)