Skip to content

Commit f8c617c

Browse files
committed
WIP OpenAI spec generation
1 parent e913512 commit f8c617c

15 files changed

+524
-33
lines changed

Diff for: src/Endpoint/Create.php

+63-1
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,23 @@
99
use Tobyz\JsonApiServer\Endpoint\Concerns\ShowsResources;
1010
use Tobyz\JsonApiServer\Exception\ForbiddenException;
1111
use Tobyz\JsonApiServer\Exception\MethodNotAllowedException;
12+
use Tobyz\JsonApiServer\JsonApi;
13+
use Tobyz\JsonApiServer\OpenApi\OpenApiPathsProvider;
14+
use Tobyz\JsonApiServer\Resource\Collection;
1215
use Tobyz\JsonApiServer\Resource\Creatable;
16+
use Tobyz\JsonApiServer\Schema\Concerns\HasDescription;
1317
use Tobyz\JsonApiServer\Schema\Concerns\HasVisibility;
1418

1519
use function Tobyz\JsonApiServer\has_value;
1620
use function Tobyz\JsonApiServer\json_api_response;
1721
use function Tobyz\JsonApiServer\set_value;
1822

19-
class Create implements Endpoint
23+
class Create implements Endpoint, OpenApiPathsProvider
2024
{
2125
use HasVisibility;
2226
use SavesData;
2327
use ShowsResources;
28+
use HasDescription;
2429

2530
public static function make(): static
2631
{
@@ -78,4 +83,61 @@ private function fillDefaultValues(Context $context, array &$data): void
7883
}
7984
}
8085
}
86+
87+
public function getOpenApiPaths(Collection $collection): array
88+
{
89+
$resourcesCreate = array_map(
90+
fn($resource) => ['$ref' => "#/components/schemas/{$resource}Create"],
91+
$collection->resources(),
92+
);
93+
94+
$resources = array_map(
95+
fn($resource) => ['$ref' => "#/components/schemas/$resource"],
96+
$collection->resources(),
97+
);
98+
99+
return [
100+
"/{$collection->name()}" => [
101+
'post' => [
102+
'description' => $this->getDescription(),
103+
'tags' => [$collection->name()],
104+
'requestBody' => [
105+
'content' => [
106+
JsonApi::MEDIA_TYPE => [
107+
'schema' => [
108+
'type' => 'object',
109+
'required' => ['data'],
110+
'properties' => [
111+
'data' =>
112+
count($resourcesCreate) === 1
113+
? $resourcesCreate[0]
114+
: ['oneOf' => $resourcesCreate],
115+
],
116+
],
117+
],
118+
],
119+
'required' => true,
120+
],
121+
'responses' => [
122+
'200' => [
123+
'content' => [
124+
JsonApi::MEDIA_TYPE => [
125+
'schema' => [
126+
'type' => 'object',
127+
'required' => ['data'],
128+
'properties' => [
129+
'data' =>
130+
count($resources) === 1
131+
? $resources[0]
132+
: ['oneOf' => $resources],
133+
],
134+
],
135+
],
136+
],
137+
],
138+
],
139+
],
140+
],
141+
];
142+
}
81143
}

Diff for: src/Endpoint/Delete.php

+28-1
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,21 @@
99
use Tobyz\JsonApiServer\Endpoint\Concerns\FindsResources;
1010
use Tobyz\JsonApiServer\Exception\ForbiddenException;
1111
use Tobyz\JsonApiServer\Exception\MethodNotAllowedException;
12+
use Tobyz\JsonApiServer\OpenApi\OpenApiPathsProvider;
13+
use Tobyz\JsonApiServer\Resource\Collection;
1214
use Tobyz\JsonApiServer\Resource\Deletable;
15+
use Tobyz\JsonApiServer\Schema\Concerns\HasDescription;
1316
use Tobyz\JsonApiServer\Schema\Concerns\HasMeta;
1417
use Tobyz\JsonApiServer\Schema\Concerns\HasVisibility;
1518

1619
use function Tobyz\JsonApiServer\json_api_response;
1720

18-
class Delete implements Endpoint
21+
class Delete implements Endpoint, OpenApiPathsProvider
1922
{
2023
use HasMeta;
2124
use HasVisibility;
2225
use FindsResources;
26+
use HasDescription;
2327

2428
public static function make(): static
2529
{
@@ -62,4 +66,27 @@ public function handle(Context $context): ?ResponseInterface
6266

6367
return new Response(204);
6468
}
69+
70+
public function getOpenApiPaths(Collection $collection): array
71+
{
72+
return [
73+
"/{$collection->name()}/{id}" => [
74+
'delete' => [
75+
'description' => $this->getDescription(),
76+
'tags' => [$collection->name()],
77+
'parameters' => [
78+
[
79+
'name' => 'id',
80+
'in' => 'path',
81+
'required' => true,
82+
'schema' => ['type' => 'string'],
83+
],
84+
],
85+
'responses' => [
86+
'204' => [],
87+
],
88+
],
89+
],
90+
];
91+
}
6592
}

Diff for: src/Endpoint/Index.php

+46-1
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,13 @@
1111
use Tobyz\JsonApiServer\Exception\ForbiddenException;
1212
use Tobyz\JsonApiServer\Exception\MethodNotAllowedException;
1313
use Tobyz\JsonApiServer\Exception\Sourceable;
14+
use Tobyz\JsonApiServer\JsonApi;
15+
use Tobyz\JsonApiServer\OpenApi\OpenApiPathsProvider;
1416
use Tobyz\JsonApiServer\Pagination\OffsetPagination;
17+
use Tobyz\JsonApiServer\Resource\Collection;
1518
use Tobyz\JsonApiServer\Resource\Countable;
1619
use Tobyz\JsonApiServer\Resource\Listable;
20+
use Tobyz\JsonApiServer\Schema\Concerns\HasDescription;
1721
use Tobyz\JsonApiServer\Schema\Concerns\HasMeta;
1822
use Tobyz\JsonApiServer\Schema\Concerns\HasVisibility;
1923
use Tobyz\JsonApiServer\Serializer;
@@ -22,11 +26,12 @@
2226
use function Tobyz\JsonApiServer\json_api_response;
2327
use function Tobyz\JsonApiServer\parse_sort_string;
2428

25-
class Index implements Endpoint
29+
class Index implements Endpoint, OpenApiPathsProvider
2630
{
2731
use HasMeta;
2832
use HasVisibility;
2933
use IncludesData;
34+
use HasDescription;
3035

3136
public Closure $paginationResolver;
3237
public ?string $defaultSort = null;
@@ -166,4 +171,44 @@ private function applyFilters($query, Context $context): void
166171
throw $e->prependSource(['parameter' => 'filter']);
167172
}
168173
}
174+
175+
public function getOpenApiPaths(Collection $collection): array
176+
{
177+
$resources = array_map(
178+
fn($resource) => [
179+
'$ref' => "#/components/schemas/$resource",
180+
],
181+
$collection->resources(),
182+
);
183+
184+
return [
185+
"/{$collection->name()}" => [
186+
'get' => [
187+
'description' => $this->getDescription(),
188+
'tags' => [$collection->name()],
189+
'responses' => [
190+
'200' => [
191+
'content' => [
192+
JsonApi::MEDIA_TYPE => [
193+
'schema' => [
194+
'type' => 'object',
195+
'required' => ['data'],
196+
'properties' => [
197+
'data' => [
198+
'type' => 'array',
199+
'items' =>
200+
count($resources) === 1
201+
? $resources[0]
202+
: ['oneOf' => $resources],
203+
],
204+
],
205+
],
206+
],
207+
],
208+
],
209+
],
210+
],
211+
],
212+
];
213+
}
169214
}

Diff for: src/Endpoint/Show.php

+49-1
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,20 @@
88
use Tobyz\JsonApiServer\Endpoint\Concerns\ShowsResources;
99
use Tobyz\JsonApiServer\Exception\ForbiddenException;
1010
use Tobyz\JsonApiServer\Exception\MethodNotAllowedException;
11+
use Tobyz\JsonApiServer\JsonApi;
12+
use Tobyz\JsonApiServer\OpenApi\OpenApiPathsProvider;
13+
use Tobyz\JsonApiServer\Resource\Collection;
14+
use Tobyz\JsonApiServer\Schema\Concerns\HasDescription;
1115
use Tobyz\JsonApiServer\Schema\Concerns\HasVisibility;
1216

1317
use function Tobyz\JsonApiServer\json_api_response;
1418

15-
class Show implements Endpoint
19+
class Show implements Endpoint, OpenApiPathsProvider
1620
{
1721
use HasVisibility;
1822
use FindsResources;
1923
use ShowsResources;
24+
use HasDescription;
2025

2126
public static function make(): static
2227
{
@@ -43,4 +48,47 @@ public function handle(Context $context): ?ResponseInterface
4348

4449
return json_api_response($this->showResource($context, $model));
4550
}
51+
52+
public function getOpenApiPaths(Collection $collection): array
53+
{
54+
$resources = array_map(
55+
fn($resource) => ['$ref' => "#/components/schemas/$resource"],
56+
$collection->resources(),
57+
);
58+
59+
return [
60+
"/{$collection->name()}/{id}" => [
61+
'get' => [
62+
'description' => $this->getDescription(),
63+
'tags' => [$collection->name()],
64+
'parameters' => [
65+
[
66+
'name' => 'id',
67+
'in' => 'path',
68+
'required' => true,
69+
'schema' => ['type' => 'string'],
70+
],
71+
],
72+
'responses' => [
73+
'200' => [
74+
'content' => [
75+
JsonApi::MEDIA_TYPE => [
76+
'schema' => [
77+
'type' => 'object',
78+
'required' => ['data'],
79+
'properties' => [
80+
'data' =>
81+
count($resources) === 1
82+
? $resources[0]
83+
: ['oneOf' => $resources],
84+
],
85+
],
86+
],
87+
],
88+
],
89+
],
90+
],
91+
],
92+
];
93+
}
4694
}

Diff for: src/Endpoint/Update.php

+74-5
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,22 @@
1010
use Tobyz\JsonApiServer\Endpoint\Concerns\ShowsResources;
1111
use Tobyz\JsonApiServer\Exception\ForbiddenException;
1212
use Tobyz\JsonApiServer\Exception\MethodNotAllowedException;
13+
use Tobyz\JsonApiServer\JsonApi;
14+
use Tobyz\JsonApiServer\OpenApi\OpenApiPathsProvider;
15+
use Tobyz\JsonApiServer\Resource\Collection;
1316
use Tobyz\JsonApiServer\Resource\Updatable;
17+
use Tobyz\JsonApiServer\Schema\Concerns\HasDescription;
1418
use Tobyz\JsonApiServer\Schema\Concerns\HasVisibility;
1519

1620
use function Tobyz\JsonApiServer\json_api_response;
1721

18-
class Update implements Endpoint
22+
class Update implements Endpoint, OpenApiPathsProvider
1923
{
2024
use HasVisibility;
2125
use FindsResources;
2226
use SavesData;
2327
use ShowsResources;
28+
use HasDescription;
2429

2530
public static function make(): static
2631
{
@@ -41,17 +46,19 @@ public function handle(Context $context): ?ResponseInterface
4146

4247
$model = $this->findResource($context, $segments[1]);
4348

44-
$context = $context->withResource(
45-
$resource = $context->resource($context->collection->resource($model, $context)),
46-
);
49+
$context = $context
50+
->withModel($model)
51+
->withResource(
52+
$resource = $context->resource($context->collection->resource($model, $context)),
53+
);
4754

4855
if (!$resource instanceof Updatable) {
4956
throw new RuntimeException(
5057
sprintf('%s must implement %s', get_class($resource), Updatable::class),
5158
);
5259
}
5360

54-
if (!$this->isVisible($context = $context->withModel($model))) {
61+
if (!$this->isVisible($context)) {
5562
throw new ForbiddenException();
5663
}
5764

@@ -68,4 +75,66 @@ public function handle(Context $context): ?ResponseInterface
6875

6976
return json_api_response($this->showResource($context, $model));
7077
}
78+
79+
public function getOpenApiPaths(Collection $collection): array
80+
{
81+
$resources = array_map(
82+
fn($resource) => [
83+
'$ref' => "#/components/schemas/$resource",
84+
],
85+
$collection->resources(),
86+
);
87+
88+
return [
89+
"/{$collection->name()}/{id}" => [
90+
'patch' => [
91+
'description' => $this->getDescription(),
92+
'tags' => [$collection->name()],
93+
'parameters' => [
94+
[
95+
'name' => 'id',
96+
'in' => 'path',
97+
'required' => true,
98+
'schema' => ['type' => 'string'],
99+
],
100+
],
101+
'requestBody' => [
102+
'content' => [
103+
JsonApi::MEDIA_TYPE => [
104+
'schema' => [
105+
'type' => 'object',
106+
'required' => ['data'],
107+
'properties' => [
108+
'data' =>
109+
count($resources) === 1
110+
? $resources[0]
111+
: ['oneOf' => $resources],
112+
],
113+
],
114+
],
115+
],
116+
'required' => true,
117+
],
118+
'responses' => [
119+
'200' => [
120+
'content' => [
121+
JsonApi::MEDIA_TYPE => [
122+
'schema' => [
123+
'type' => 'object',
124+
'required' => ['data'],
125+
'properties' => [
126+
'data' =>
127+
count($resources) === 1
128+
? $resources[0]
129+
: ['oneOf' => $resources],
130+
],
131+
],
132+
],
133+
],
134+
],
135+
],
136+
],
137+
],
138+
];
139+
}
71140
}

0 commit comments

Comments
 (0)