Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions docs/openapi/components.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -153,15 +153,15 @@ $components = Components::create()
);
```

Reference them from operations with `Response::ref()`. A reference carries no status code, so pass it to `response()` along with the code it answers:
Reference them from operations with `->ref()`, which keeps the status code from the named constructor:

```php
Operation::get()
->responses(
Response::ok()->json(Reference::schema('User')),
)
->response(404, Response::ref('NotFound'))
->response(401, Response::ref('Unauthorized'));
Response::notFound()->ref('NotFound'),
Response::unauthorized()->ref('Unauthorized'),
);
```

## Request Bodies
Expand All @@ -184,8 +184,8 @@ $components = Components::create()
);

// Reference
Operation::post()->requestBody(RequestBody::ref('CreateUser'));
Operation::patch()->requestBody(RequestBody::ref('UpdateUser'));
Operation::post()->requestBody(Reference::requestBody('CreateUser'));
Operation::patch()->requestBody(Reference::requestBody('UpdateUser'));
```

## Security Schemes
Expand Down
15 changes: 10 additions & 5 deletions docs/openapi/paths-and-operations.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ Operation::get()

### Attaching Responses

`responses()` takes `Response` objects and keys them from their own status code, so you rarely repeat yourself. A `$ref` has no status code of its own, so pass those to `response()` with an explicit key:
`responses()` takes `Response` objects and keys them from their own status code, so you rarely repeat yourself. Point a status code at a reusable response with `->ref()`:

```php
use Cortex\OpenApi\Objects\Response;
Expand All @@ -147,12 +147,17 @@ use Cortex\OpenApi\Objects\Reference;
Operation::get()
->responses(
Response::ok()->json(Reference::schema('Article')),
)
->response(404, Response::ref('NotFound'))
->response(401, Response::ref('Unauthorized'));
Response::notFound()->ref('NotFound'),
);
```

`responses()` replaces the whole map, so call it first and add any references with `response()` afterwards.
`response()` sets a single status key, which is useful for a code with no named constructor or when adding to an existing map — `responses()` replaces the map wholesale:

```php
Operation::get()
->responses(Response::ok()->json(Reference::schema('Article')))
->response(418, Reference::response('Teapot'));
```

See [Responses](/openapi/responses) for headers, links, and reusable response components.

Expand Down
16 changes: 8 additions & 8 deletions docs/openapi/quickstart.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -277,14 +277,14 @@ Reference::example('AdminUser') // #/components/examples/AdminUser
Reference::callback('EventWebhook') // #/components/callbacks/EventWebhook
Reference::pathItem('LegacyPets') // #/components/pathItems/LegacyPets

// Generic reference — use when the bucket isn't covered above
Reference::to('#/components/schemas/Pet')

// Shortcut on the target class (equivalent, and communicates intent)
Response::ref('NotFound') // pass to Operation::response($status, ...)
Parameter::ref('PetId')
RequestBody::ref('CreateUser')
Example::ref('AdminUser')
// Generic reference — for a pointer outside the component buckets
Reference::to('./common.yaml#/components/schemas/Pet')
```

Every reference is built here, so there is one place to look and one spelling to remember. The exception is a response inside `Operation::responses()`, which needs a status code to key on — see [Responses](/openapi/responses):

```php
Response::notFound()->ref('NotFound')
```

## Vendor Extensions
Expand Down
2 changes: 1 addition & 1 deletion docs/openapi/request-bodies.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ $components = Components::create()
// Reference from an operation
Operation::post()
->operationId('articles.create')
->requestBody(RequestBody::ref('CreateArticle'));
->requestBody(Reference::requestBody('CreateArticle'));
```

## Complete Example
Expand Down
26 changes: 19 additions & 7 deletions docs/openapi/responses.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ icon: 'file-down'

## Response

`Response` describes a single HTTP status code outcome. Pass one or more of them to `Operation::responses()` and each is keyed from its own status code. References carry no status code, so attach those with `->response()`:
`Response` describes a single HTTP status code outcome. Pass one or more of them to `Operation::responses()` and each is keyed from its own status code:

```php
use Cortex\OpenApi\Objects\Response;
Expand All @@ -18,13 +18,23 @@ Operation::get()
Response::ok()->json(Reference::schema('User')),
Response::notFound()->json(Reference::schema('Error')),
);
```

To answer a status code with a reusable response from `Components`, use `->ref()`. The status still comes from the named constructor, so it belongs in the same `responses()` call:

// A reusable component response — the status code is the first argument
```php
Operation::get()
->responses(Response::ok()->json(Reference::schema('User')))
->response(404, Response::ref('NotFound'));
->responses(
Response::ok()->json(Reference::schema('User')),
Response::notFound()->ref('NotFound'),
Response::unauthorized()->ref('Unauthorized'),
);
```

<Tip>
Elsewhere, references are built with `Reference::response('NotFound')` — see [Working with References](/openapi/quickstart). `->ref()` exists on `Response` because `responses()` keys each entry by status code, and a bare reference has none. Slots that supply the status themselves, such as `Components::response()` and `Operation::response(404, ...)`, take `Reference::response()`.
</Tip>

### Named Constructors

Every common HTTP status code has a named constructor that pre-populates the standard description. Override it with `->description()`.
Expand Down Expand Up @@ -202,9 +212,11 @@ $components = Components::create()

// Reference from an operation
Operation::get()
->responses(Response::ok()->json($schema))
->response(404, Response::ref('NotFound'))
->response(401, Response::ref('Unauthorized'));
->responses(
Response::ok()->json($schema),
Response::notFound()->ref('NotFound'),
Response::unauthorized()->ref('Unauthorized'),
);
```

## Inline Examples on Responses
Expand Down
6 changes: 3 additions & 3 deletions docs/openapi/webhooks-and-callbacks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ Operation::post()

```php
Operation::post()
->callback('onEvent', Callback::ref('EventWebhook'))
->callback('onEvent', Reference::callback('EventWebhook'))
->callback('onError', Callback::create()->expression(
'{$request.body#/errorUrl}',
PathItem::create('')->operations(
Expand Down Expand Up @@ -257,7 +257,7 @@ $components = Components::create()
Operation::post()
->operationId('hooks.subscribe')
->callbacks([
'onEvent' => Callback::ref('EventWebhook'),
'onEvent' => Reference::callback('EventWebhook'),
]);
```

Expand Down Expand Up @@ -339,7 +339,7 @@ $doc = OpenApi::create()
)
->responses(Response::created())
->callbacks([
'onEvent' => Callback::ref('GenericWebhook'),
'onEvent' => Reference::callback('GenericWebhook'),
]),
),
);
Expand Down
5 changes: 0 additions & 5 deletions src/Objects/Callback.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,6 @@ public static function create(): self
return new self();
}

public static function ref(string $name, ?string $summary = null, ?string $description = null): Reference
{
return Reference::callback($name, $summary, $description);
}

public function expression(string $runtimeExpression, PathItem $pathItem): self
{
$this->expressions[$runtimeExpression] = $pathItem;
Expand Down
5 changes: 0 additions & 5 deletions src/Objects/Example.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,6 @@ public static function create(): self
return new self();
}

public static function ref(string $name, ?string $summary = null, ?string $description = null): Reference
{
return Reference::example($name, $summary, $description);
}

public function summary(?string $summary): self
{
$this->summary = $summary;
Expand Down
5 changes: 0 additions & 5 deletions src/Objects/Header.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,6 @@ public static function create(): self
return new self();
}

public static function ref(string $name, ?string $summary = null, ?string $description = null): Reference
{
return Reference::header($name, $summary, $description);
}

public function description(?string $description): self
{
$this->description = $description;
Expand Down
5 changes: 0 additions & 5 deletions src/Objects/Link.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,6 @@ public static function create(): self
return new self();
}

public static function ref(string $name, ?string $summary = null, ?string $description = null): Reference
{
return Reference::link($name, $summary, $description);
}

public function operationRef(?string $operationRef): self
{
$this->operationRef = $operationRef;
Expand Down
5 changes: 0 additions & 5 deletions src/Objects/Parameter.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,6 @@ public static function cookie(string $name, JsonSchema|array|Reference|null $sch
return new self($name, In::Cookie, $schema);
}

public static function ref(string $name, ?string $summary = null, ?string $description = null): Reference
{
return Reference::parameter($name, $summary, $description);
}

public function getName(): string
{
return $this->name;
Expand Down
5 changes: 0 additions & 5 deletions src/Objects/PathItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,6 @@ public static function create(string $path): self
return new self($path);
}

public static function ref(string $name, ?string $summary = null, ?string $description = null): Reference
{
return Reference::pathItem($name, $summary, $description);
}

public function getPath(): string
{
return $this->path;
Expand Down
5 changes: 0 additions & 5 deletions src/Objects/RequestBody.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,6 @@ public static function create(): self
return new self();
}

public static function ref(string $name, ?string $summary = null, ?string $description = null): Reference
{
return Reference::requestBody($name, $summary, $description);
}

public function description(?string $description): self
{
$this->description = $description;
Expand Down
19 changes: 17 additions & 2 deletions src/Objects/Response.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ final class Response implements Serializable, HasExtensionsInterface

private ?string $description;

private ?Reference $reference = null;

/**
* @var array<string, Header|Reference>
*/
Expand Down Expand Up @@ -126,9 +128,18 @@ public static function internalServerError(): self
return new self('500');
}

public static function ref(string $name, ?string $summary = null, ?string $description = null): Reference
/**
* Answer this status code with a reusable response from Components.
*
* The status code is kept, so the result can go straight into Operation::responses().
* The document carries the $ref alone — a Reference Object has no room for the other
* fields set on this response.
*/
public function ref(string $name, ?string $summary = null, ?string $description = null): self
{
return Reference::response($name, $summary, $description);
$this->reference = Reference::response($name, $summary, $description);

return $this;
}

public function getStatusCode(): string
Expand Down Expand Up @@ -203,6 +214,10 @@ public function link(string $name, Link|Reference $link): self
*/
public function toArray(): array
{
if ($this->reference instanceof Reference) {
return $this->reference->toArray();
}

return $this->buildArray([
'description' => $this->description,
'headers' => $this->headers,
Expand Down
5 changes: 0 additions & 5 deletions src/Objects/SecurityScheme.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,6 @@ public static function mutualTls(): self
return new self(SecuritySchemeType::MutualTls);
}

public static function ref(string $name, ?string $summary = null, ?string $description = null): Reference
{
return Reference::securityScheme($name, $summary, $description);
}

public function getType(): SecuritySchemeType
{
return $this->securitySchemeType;
Expand Down
6 changes: 0 additions & 6 deletions tests/Unit/Objects/CallbackTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,3 @@
],
]);
});

it('supports ref() shortcut', function (): void {
expect(Callback::ref('Webhook')->toArray())->toBe([
'$ref' => '#/components/callbacks/Webhook',
]);
});
6 changes: 0 additions & 6 deletions tests/Unit/Objects/ExampleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,6 @@
]);
});

it('supports ref() shortcut', function (): void {
expect(Example::ref('SampleUser')->toArray())->toBe([
'$ref' => '#/components/examples/SampleUser',
]);
});

it('clears a value when explicitly cleared', function (): void {
$example = Example::create()->value('a');

Expand Down
6 changes: 0 additions & 6 deletions tests/Unit/Objects/HeaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,6 @@
]);
});

it('supports ref() shortcut', function (): void {
expect(Header::ref('RateLimitRemaining')->toArray())->toBe([
'$ref' => '#/components/headers/RateLimitRemaining',
]);
});

it('accepts a Style enum for style()', function (): void {
$header = Header::create()->style(Style::Simple);

Expand Down
6 changes: 0 additions & 6 deletions tests/Unit/Objects/LinkTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,6 @@
]);
});

it('supports ref() shortcut', function (): void {
expect(Link::ref('Foo')->toArray())->toBe([
'$ref' => '#/components/links/Foo',
]);
});

it('inserts requestBody after parameters when parameters are present', function (): void {
$link = Link::create()
->operationId('users.create')
Expand Down
18 changes: 17 additions & 1 deletion tests/Unit/Objects/OperationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,22 @@
expect($operation->toArray()['responses'])->toHaveKeys(['200', '404']);
});

it('responses() accepts a referenced response and keys it by status', function (): void {
$operation = Operation::get()->responses(
Response::ok(),
Response::notFound()->ref('NotFound'),
);

expect($operation->toArray()['responses'])->toBe([
'200' => [
'description' => 'OK',
],
'404' => [
'$ref' => '#/components/responses/NotFound',
],
]);
});

it('adds a response by explicit status key, accepting Response or Reference', function (): void {
$operation = Operation::get()
->response('200', Response::ok())
Expand All @@ -179,7 +195,7 @@
it('adds callbacks one at a time with callback()', function (): void {
$operation = Operation::post()
->callback('onData', Callback::create()->expression('{$url}', PathItem::create('/hook')))
->callback('onError', Callback::ref('OnError'));
->callback('onError', Reference::callback('OnError'));

$arr = $operation->toArray();
expect($arr['callbacks'])->toHaveKey('onData');
Expand Down
Loading