Skip to content

Commit 7ad2380

Browse files
committed
docs: Add docs and covers
1 parent a92cc7e commit 7ad2380

38 files changed

Lines changed: 2613 additions & 2 deletions

docs/docs.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,18 @@
3333
"openapi/installation",
3434
"openapi/quickstart"
3535
]
36+
},
37+
{
38+
"group": "Core Concepts",
39+
"pages": [
40+
"openapi/info-and-metadata",
41+
"openapi/paths-and-operations",
42+
"openapi/request-bodies",
43+
"openapi/responses",
44+
"openapi/components",
45+
"openapi/security",
46+
"openapi/webhooks-and-callbacks"
47+
]
3648
}
3749
]
3850
}

docs/openapi/components.mdx

Lines changed: 344 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,344 @@
1+
---
2+
title: Components
3+
description: 'Centralize reusable definitions and reference them with $ref'
4+
icon: 'box'
5+
---
6+
7+
## Why Components?
8+
9+
The `components` section is a central registry for anything you want to reuse. Once registered, any object can be referenced anywhere in the document with a `$ref` pointer instead of being repeated inline. This means a schema change only needs to happen in one place, and documentation tools render the component name as a clickable type link.
10+
11+
```php
12+
use Cortex\OpenApi\Objects\Components;
13+
14+
$components = Components::create()
15+
->schema('User', $userSchema)
16+
->response('NotFound', Response::notFound()->content(MediaType::json($errorSchema)))
17+
->parameter('PageSize', Parameter::query('pageSize', Schema::integer()->minimum(1)->maximum(100)))
18+
->securityScheme('BearerAuth', SecurityScheme::http('bearer')->bearerFormat('JWT'));
19+
```
20+
21+
## What Can Be Registered
22+
23+
Components supports ten registries, each addressable by its own `$ref` path:
24+
25+
| Registry | Method | $ref prefix |
26+
|----------|--------|-------------|
27+
| Schemas | `->schema(name, schema)` | `#/components/schemas/` |
28+
| Responses | `->response(name, response)` | `#/components/responses/` |
29+
| Parameters | `->parameter(name, parameter)` | `#/components/parameters/` |
30+
| Examples | `->example(name, example)` | `#/components/examples/` |
31+
| Request Bodies | `->requestBody(name, body)` | `#/components/requestBodies/` |
32+
| Headers | `->header(name, header)` | `#/components/headers/` |
33+
| Security Schemes | `->securityScheme(name, scheme)` | `#/components/securitySchemes/` |
34+
| Links | `->link(name, link)` | `#/components/links/` |
35+
| Callbacks | `->callback(name, callback)` | `#/components/callbacks/` |
36+
| Path Items | `->pathItem(name, pathItem)` | `#/components/pathItems/` |
37+
38+
## Schemas
39+
40+
Register any `cortexphp/json-schema` schema or raw array by name:
41+
42+
```php
43+
use Cortex\JsonSchema\Schema;
44+
45+
$components = Components::create()
46+
->schema('User', Schema::object()->properties(
47+
Schema::integer('id')->format('int64')->required(),
48+
Schema::string('name')->required(),
49+
Schema::string('email')->format('email')->required(),
50+
Schema::string('role')->enum(['admin', 'editor', 'viewer'])->default('viewer'),
51+
))
52+
->schema('Error', Schema::object()->properties(
53+
Schema::integer('code')->format('int32')->required(),
54+
Schema::string('message')->required(),
55+
))
56+
->schema('Pagination', Schema::object()->properties(
57+
Schema::integer('total')->required(),
58+
Schema::integer('page')->required(),
59+
Schema::integer('perPage')->required(),
60+
Schema::boolean('hasMore')->required(),
61+
));
62+
```
63+
64+
Reference schemas anywhere with `Reference::to()`:
65+
66+
```php
67+
use Cortex\OpenApi\Objects\Reference;
68+
69+
// In a MediaType
70+
MediaType::json(Reference::to('#/components/schemas/User'))
71+
72+
// In a Parameter schema slot
73+
Parameter::query('filter', Reference::to('#/components/schemas/Filter'))
74+
75+
// In a composed schema (allOf/oneOf/anyOf)
76+
Schema::object()->allOf(
77+
Reference::to('#/components/schemas/BaseEntity'),
78+
Schema::object()->properties(Schema::string('title')),
79+
)
80+
```
81+
82+
## Parameters
83+
84+
Shared parameters — particularly path parameters that appear on multiple paths — are ideal candidates for components:
85+
86+
```php
87+
use Cortex\OpenApi\Objects\Parameter;
88+
89+
$components = Components::create()
90+
->parameter('UserId',
91+
Parameter::path('userId', Schema::integer()->format('int64'))
92+
->description('The unique user identifier'),
93+
)
94+
->parameter('ArticleSlug',
95+
Parameter::path('slug', Schema::string()->pattern('^[a-z0-9-]+$'))
96+
->description('The article slug'),
97+
)
98+
->parameter('PageSize',
99+
Parameter::query('pageSize', Schema::integer()->minimum(1)->maximum(100)->default(20))
100+
->description('Number of results per page'),
101+
)
102+
->parameter('PageNumber',
103+
Parameter::query('page', Schema::integer()->minimum(1)->default(1))
104+
->description('Page number'),
105+
);
106+
```
107+
108+
Reference parameters from path items:
109+
110+
```php
111+
use Cortex\OpenApi\Objects\PathItem;
112+
113+
PathItem::create('/users/{userId}/articles/{slug}')
114+
->parameters(
115+
Reference::to('#/components/parameters/UserId'),
116+
Reference::to('#/components/parameters/ArticleSlug'),
117+
)
118+
->operations(
119+
Operation::get()
120+
->operationId('users.articles.show')
121+
->parameters(
122+
Reference::to('#/components/parameters/PageSize'),
123+
Reference::to('#/components/parameters/PageNumber'),
124+
),
125+
);
126+
```
127+
128+
## Responses
129+
130+
Centralize common error responses to avoid repeating them on every operation:
131+
132+
```php
133+
use Cortex\OpenApi\Objects\Response;
134+
use Cortex\OpenApi\Objects\MediaType;
135+
136+
$errorSchema = Reference::to('#/components/schemas/Error');
137+
138+
$components = Components::create()
139+
->response('BadRequest',
140+
Response::badRequest()->content(MediaType::json($errorSchema)),
141+
)
142+
->response('Unauthorized',
143+
Response::unauthorized()->content(MediaType::json($errorSchema)),
144+
)
145+
->response('Forbidden',
146+
Response::forbidden()->content(MediaType::json($errorSchema)),
147+
)
148+
->response('NotFound',
149+
Response::notFound()->content(MediaType::json($errorSchema)),
150+
)
151+
->response('UnprocessableEntity',
152+
Response::unprocessable()->content(MediaType::json($errorSchema)),
153+
);
154+
```
155+
156+
Reference them from operations using `Response::ref()`:
157+
158+
```php
159+
Operation::get()
160+
->responses(
161+
Response::ok()->content(MediaType::json(Reference::to('#/components/schemas/User'))),
162+
Response::ref('#/components/responses/NotFound'),
163+
Response::ref('#/components/responses/Unauthorized'),
164+
);
165+
```
166+
167+
## Request Bodies
168+
169+
Shared request body definitions are useful when multiple operations accept the same payload shape:
170+
171+
```php
172+
use Cortex\OpenApi\Objects\RequestBody;
173+
174+
$components = Components::create()
175+
->requestBody('CreateUser',
176+
RequestBody::create()
177+
->required(true)
178+
->content(MediaType::json(Reference::to('#/components/schemas/UserInput'))),
179+
)
180+
->requestBody('UpdateUser',
181+
RequestBody::create()
182+
->required(true)
183+
->content(MediaType::json(Reference::to('#/components/schemas/UserPatch'))),
184+
);
185+
186+
// Reference
187+
Operation::post()->requestBody(RequestBody::ref('#/components/requestBodies/CreateUser'));
188+
Operation::patch()->requestBody(RequestBody::ref('#/components/requestBodies/UpdateUser'));
189+
```
190+
191+
## Security Schemes
192+
193+
Security schemes are almost always defined in components and referenced from operations or the document root:
194+
195+
```php
196+
use Cortex\OpenApi\Objects\SecurityScheme;
197+
use Cortex\OpenApi\Objects\OAuthFlows;
198+
use Cortex\OpenApi\Objects\OAuthFlow;
199+
use Cortex\OpenApi\Enums\In;
200+
201+
$components = Components::create()
202+
->securityScheme('BearerAuth',
203+
SecurityScheme::http('bearer')
204+
->bearerFormat('JWT')
205+
->description('JWT Bearer token from /auth/token'),
206+
)
207+
->securityScheme('ApiKey',
208+
SecurityScheme::apiKey('X-API-Key', In::Header)
209+
->description('API key passed in the X-API-Key header'),
210+
)
211+
->securityScheme('OAuth2',
212+
SecurityScheme::oauth2(
213+
OAuthFlows::create()->authorizationCode(
214+
OAuthFlow::create()
215+
->authorizationUrl('https://auth.example.com/oauth/authorize')
216+
->tokenUrl('https://auth.example.com/oauth/token')
217+
->scopes([
218+
'read:users' => 'Read user profiles',
219+
'write:users' => 'Create and modify users',
220+
]),
221+
),
222+
),
223+
);
224+
```
225+
226+
See [Security](/openapi/security) for full coverage of authentication schemes.
227+
228+
## Headers
229+
230+
Shared response headers — such as rate-limit or tracing headers — can be registered once:
231+
232+
```php
233+
use Cortex\OpenApi\Objects\Header;
234+
235+
$components = Components::create()
236+
->header('X-Request-Id',
237+
Header::create()
238+
->schema(Schema::string()->format('uuid'))
239+
->description('Echoed back for distributed tracing'),
240+
)
241+
->header('X-RateLimit-Remaining',
242+
Header::create()
243+
->schema(Schema::integer())
244+
->description('Number of requests remaining in the current window'),
245+
);
246+
```
247+
248+
Reference headers in a response's `->headers()` array:
249+
250+
```php
251+
Response::ok()->headers([
252+
'X-Request-Id' => Reference::to('#/components/headers/X-Request-Id'),
253+
'X-RateLimit-Remaining' => Reference::to('#/components/headers/X-RateLimit-Remaining'),
254+
])
255+
```
256+
257+
## Examples
258+
259+
Register named examples in components for reuse across multiple parameters, request bodies, and responses:
260+
261+
```php
262+
use Cortex\OpenApi\Objects\Example;
263+
264+
$components = Components::create()
265+
->example('AdminUser', Example::create()
266+
->summary('An admin user')
267+
->value(['id' => 1, 'name' => 'Admin', 'role' => 'admin']))
268+
->example('EditorUser', Example::create()
269+
->summary('An editor user')
270+
->value(['id' => 2, 'name' => 'Editor', 'role' => 'editor']));
271+
```
272+
273+
## Path Items
274+
275+
`pathItems` in components is a newer addition (OpenAPI 3.1) that lets you define reusable path item templates — useful for webhooks:
276+
277+
```php
278+
$components = Components::create()
279+
->pathItem('UserEvent',
280+
PathItem::create('')
281+
->operations(
282+
Operation::post()
283+
->operationId('webhook.user.event')
284+
->requestBody(
285+
RequestBody::create()
286+
->content(MediaType::json(Reference::to('#/components/schemas/UserEvent'))),
287+
)
288+
->responses(Response::ok()),
289+
),
290+
);
291+
```
292+
293+
## Putting It Together
294+
295+
A realistic components setup combining schemas, security, and shared responses:
296+
297+
```php
298+
use Cortex\JsonSchema\Schema;
299+
use Cortex\OpenApi\Objects\Components;
300+
use Cortex\OpenApi\Objects\Parameter;
301+
use Cortex\OpenApi\Objects\Response;
302+
use Cortex\OpenApi\Objects\MediaType;
303+
use Cortex\OpenApi\Objects\SecurityScheme;
304+
use Cortex\OpenApi\Objects\OAuthFlows;
305+
use Cortex\OpenApi\Objects\OAuthFlow;
306+
use Cortex\OpenApi\Objects\Reference;
307+
308+
$components = Components::create()
309+
// Schemas
310+
->schema('User', Schema::object()->properties(
311+
Schema::integer('id')->required(),
312+
Schema::string('name')->required(),
313+
Schema::string('email')->format('email')->required(),
314+
))
315+
->schema('Error', Schema::object()->properties(
316+
Schema::string('message')->required(),
317+
Schema::array('errors')->items(Schema::string()),
318+
))
319+
320+
// Shared parameters
321+
->parameter('PageSize',
322+
Parameter::query('pageSize', Schema::integer()->minimum(1)->maximum(100)->default(20)),
323+
)
324+
->parameter('PageNumber',
325+
Parameter::query('page', Schema::integer()->minimum(1)->default(1)),
326+
)
327+
328+
// Shared responses
329+
->response('NotFound',
330+
Response::notFound()->content(
331+
MediaType::json(Reference::to('#/components/schemas/Error')),
332+
),
333+
)
334+
->response('Unauthorized',
335+
Response::unauthorized()->content(
336+
MediaType::json(Reference::to('#/components/schemas/Error')),
337+
),
338+
)
339+
340+
// Security
341+
->securityScheme('BearerAuth',
342+
SecurityScheme::http('bearer')->bearerFormat('JWT'),
343+
);
344+
```

0 commit comments

Comments
 (0)