diff --git a/src/Objects/BaseObject.php b/src/Objects/BaseObject.php index e97b704..62db193 100644 --- a/src/Objects/BaseObject.php +++ b/src/Objects/BaseObject.php @@ -161,4 +161,14 @@ public function __get(string $name) throw new PropertyDoesNotExistException("[{$name}] is not a valid property."); } + + public static function __set_state(array $properties) + { + $obj = new static($properties['objectId']); + + $obj->ref = $properties['ref']; + $obj->extensions = $properties['extensions']; + + return $obj; + } } diff --git a/src/Objects/Components.php b/src/Objects/Components.php index f75a650..e0c9874 100644 --- a/src/Objects/Components.php +++ b/src/Objects/Components.php @@ -243,4 +243,18 @@ protected function generate(): array 'callbacks' => $callbacks ?: null, ]); } + + public static function __set_state(array $properties) + { + return parent::__set_state($properties) + ->schemas(...($properties['schemas'] ?? [])) + ->responses(...($properties['responses'] ?? [])) + ->parameters(...($properties['parameters'] ?? [])) + ->examples(...($properties['examples'] ?? [])) + ->requestBodies(...($properties['requestBodies'] ?? [])) + ->headers(...($properties['headers'] ?? [])) + ->securitySchemes(...($properties['securitySchemes'] ?? [])) + ->links(...($properties['links'] ?? [])) + ->callbacks(...($properties['callbacks'] ?? [])); + } } diff --git a/src/Objects/Contact.php b/src/Objects/Contact.php index 3c2fe38..7fbd4d3 100644 --- a/src/Objects/Contact.php +++ b/src/Objects/Contact.php @@ -78,4 +78,12 @@ protected function generate(): array 'email' => $this->email, ]); } + + public static function __set_state(array $properties) + { + return parent::__set_state($properties) + ->name($properties['name']) + ->url($properties['url']) + ->email($properties['email']); + } } diff --git a/src/Objects/Discriminator.php b/src/Objects/Discriminator.php index 7e3b117..696db0c 100644 --- a/src/Objects/Discriminator.php +++ b/src/Objects/Discriminator.php @@ -69,4 +69,11 @@ protected function generate(): array 'mapping' => $this->mapping, ]); } + + public static function __set_state(array $properties) + { + return parent::__set_state($properties) + ->propertyName($properties['propertyName']) + ->mapping($properties['mapping']); + } } diff --git a/src/Objects/Encoding.php b/src/Objects/Encoding.php index bb7bc43..18b28c8 100644 --- a/src/Objects/Encoding.php +++ b/src/Objects/Encoding.php @@ -123,4 +123,14 @@ protected function generate(): array 'allowReserved' => $this->allowReserved, ]); } + + public static function __set_state(array $properties) + { + return parent::__set_state($properties) + ->contentType($properties['contentType']) + ->headers(...($properties['headers'] ?? [])) + ->style($properties['style']) + ->explode($properties['explode']) + ->allowReserved($properties['allowReserved']); + } } diff --git a/src/Objects/Example.php b/src/Objects/Example.php index 0e19d69..82b2467 100644 --- a/src/Objects/Example.php +++ b/src/Objects/Example.php @@ -98,4 +98,13 @@ protected function generate(): array 'externalValue' => $this->externalValue, ]); } + + public static function __set_state(array $properties) + { + return parent::__set_state($properties) + ->summary($properties['summary']) + ->description($properties['description']) + ->value($properties['value']) + ->externalValue($properties['externalValue']); + } } diff --git a/src/Objects/ExternalDocs.php b/src/Objects/ExternalDocs.php index 6ea983d..cbf64e9 100644 --- a/src/Objects/ExternalDocs.php +++ b/src/Objects/ExternalDocs.php @@ -58,4 +58,11 @@ protected function generate(): array 'url' => $this->url, ]); } + + public static function __set_state(array $properties) + { + return parent::__set_state($properties) + ->description($properties['description']) + ->url($properties['url']); + } } diff --git a/src/Objects/Header.php b/src/Objects/Header.php index 7241192..5e5ea20 100644 --- a/src/Objects/Header.php +++ b/src/Objects/Header.php @@ -257,4 +257,20 @@ protected function generate(): array 'content' => $content ?: null, ]); } + + public static function __set_state(array $properties) + { + return parent::__set_state($properties) + ->description($properties['description']) + ->required($properties['required']) + ->deprecated($properties['deprecated']) + ->allowEmptyValue($properties['allowEmptyValue']) + ->style($properties['style']) + ->explode($properties['explode']) + ->allowReserved($properties['allowReserved']) + ->schema($properties['schema']) + ->example($properties['example']) + ->examples(...($properties['examples'] ?? [])) + ->content(...($properties['content'] ?? [])); + } } diff --git a/src/Objects/Info.php b/src/Objects/Info.php index 24e4bc9..b357f67 100644 --- a/src/Objects/Info.php +++ b/src/Objects/Info.php @@ -138,4 +138,15 @@ protected function generate(): array 'version' => $this->version, ]); } + + public static function __set_state(array $properties) + { + return parent::__set_state($properties) + ->title($properties['title']) + ->description($properties['description']) + ->termsOfService($properties['termsOfService']) + ->contact($properties['contact']) + ->license($properties['license']) + ->version($properties['version']); + } } diff --git a/src/Objects/License.php b/src/Objects/License.php index 3af1c55..f55fc92 100644 --- a/src/Objects/License.php +++ b/src/Objects/License.php @@ -58,4 +58,11 @@ protected function generate(): array 'url' => $this->url, ]); } + + public static function __set_state(array $properties) + { + return parent::__set_state($properties) + ->name($properties['name']) + ->url($properties['url']); + } } diff --git a/src/Objects/Link.php b/src/Objects/Link.php index 5908444..e8d7558 100644 --- a/src/Objects/Link.php +++ b/src/Objects/Link.php @@ -98,4 +98,13 @@ protected function generate(): array 'server' => $this->server, ]); } + + public static function __set_state(array $properties) + { + return parent::__set_state($properties) + ->operationRef($properties['operationRef']) + ->operationId($properties['operationId']) + ->description($properties['description']) + ->server($properties['server']); + } } diff --git a/src/Objects/MediaType.php b/src/Objects/MediaType.php index 5bc8ed7..6f63dac 100644 --- a/src/Objects/MediaType.php +++ b/src/Objects/MediaType.php @@ -217,4 +217,14 @@ protected function generate(): array 'encoding' => $encodings ?: null, ]); } + + public static function __set_state(array $properties) + { + return parent::__set_state($properties) + ->mediaType($properties['mediaType']) + ->schema($properties['schema']) + ->example($properties['example']) + ->examples(...($properties['examples'] ?? [])) + ->encoding(...($properties['encoding'] ?? [])); + } } diff --git a/src/Objects/Not.php b/src/Objects/Not.php index 0651389..a10eb63 100644 --- a/src/Objects/Not.php +++ b/src/Objects/Not.php @@ -39,4 +39,10 @@ protected function generate(): array 'not' => $this->schema, ]); } + + public static function __set_state(array $properties) + { + return parent::__set_state($properties) + ->schema($properties['schema']); + } } diff --git a/src/Objects/OAuthFlow.php b/src/Objects/OAuthFlow.php index 94ebc95..a5b66ce 100644 --- a/src/Objects/OAuthFlow.php +++ b/src/Objects/OAuthFlow.php @@ -105,6 +105,14 @@ public function refreshUrl(?string $refreshUrl): self */ public function scopes(?array $scopes): self { + $instance = clone $this; + + if ($scopes === null) { + $instance->scopes = null; + + return $instance; + } + // Ensure the scopes are string => string. foreach ($scopes as $key => $value) { if (is_string($key) && is_string($value)) { @@ -114,8 +122,6 @@ public function scopes(?array $scopes): self throw new InvalidArgumentException('Each scope must have a string key and a string value.'); } - $instance = clone $this; - $instance->scopes = $scopes; return $instance; @@ -133,4 +139,14 @@ protected function generate(): array 'scopes' => $this->scopes, ]); } + + public static function __set_state(array $properties) + { + return parent::__set_state($properties) + ->flow($properties['flow']) + ->authorizationUrl($properties['authorizationUrl']) + ->tokenUrl($properties['tokenUrl']) + ->refreshUrl($properties['refreshUrl']) + ->scopes($properties['scopes']); + } } diff --git a/src/Objects/Operation.php b/src/Objects/Operation.php index b527493..a80fce8 100644 --- a/src/Objects/Operation.php +++ b/src/Objects/Operation.php @@ -400,4 +400,23 @@ protected function generate(): array 'callbacks' => $callbacks ?: null, ]); } + + public static function __set_state(array $properties) + { + return parent::__set_state($properties) + ->action($properties['action']) + ->tags(...($properties['tags'] ?? [])) + ->summary($properties['summary']) + ->description($properties['description']) + ->externalDocs($properties['externalDocs']) + ->operationId($properties['operationId']) + ->parameters(...($properties['parameters'] ?? [])) + ->requestBody($properties['requestBody']) + ->responses(...($properties['responses'] ?? [])) + ->deprecated($properties['deprecated']) + ->security(...($properties['security'] ?? [])) + ->noSecurity($properties['noSecurity']) + ->servers(...($properties['servers'] ?? [])) + ->callbacks(...($properties['callbacks'] ?? [])); + } } diff --git a/src/Objects/Parameter.php b/src/Objects/Parameter.php index 02710ab..ddba9b0 100644 --- a/src/Objects/Parameter.php +++ b/src/Objects/Parameter.php @@ -338,4 +338,23 @@ protected function generate(): array 'content' => $content ?: null, ]); } + + public static function __set_state(array $properties) + { + return parent::__set_state($properties) + ->name($properties['name']) + ->in($properties['in']) + ->description($properties['description']) + ->required($properties['required']) + ->deprecated($properties['deprecated']) + ->allowEmptyValue($properties['allowEmptyValue']) + ->style($properties['style']) + ->explode($properties['explode']) + ->allowReserved($properties['allowReserved']) + ->schema($properties['schema']) + ->example($properties['example']) + ->examples(...$properties['examples'] ?? []) + ->content(...$properties['content'] ?? []); + + } } diff --git a/src/Objects/PathItem.php b/src/Objects/PathItem.php index 3948b16..2b6e0e6 100644 --- a/src/Objects/PathItem.php +++ b/src/Objects/PathItem.php @@ -143,4 +143,15 @@ protected function generate(): array ]) ); } + + public static function __set_state(array $properties) + { + return parent::__set_state($properties) + ->route($properties['route']) + ->summary($properties['summary']) + ->description($properties['description']) + ->operations(...$properties['operations'] ?? []) + ->servers(...$properties['servers'] ?? []) + ->parameters(...$properties['parameters'] ?? []); + } } diff --git a/src/Objects/RequestBody.php b/src/Objects/RequestBody.php index 8eec78c..cef6c87 100644 --- a/src/Objects/RequestBody.php +++ b/src/Objects/RequestBody.php @@ -83,4 +83,12 @@ protected function generate(): array 'required' => $this->required, ]); } + + public static function __set_state(array $properties) + { + return parent::__set_state($properties) + ->description($properties['description']) + ->content(...($properties['content'] ?? [])) + ->required($properties['required']); + } } diff --git a/src/Objects/Response.php b/src/Objects/Response.php index ff6f98b..e9b9e01 100644 --- a/src/Objects/Response.php +++ b/src/Objects/Response.php @@ -253,4 +253,14 @@ protected function generate(): array 'links' => $links ?: null, ]); } + + public static function __set_state(array $properties) + { + return parent::__set_state($properties) + ->statusCode($properties['statusCode']) + ->description($properties['description']) + ->headers(...$properties['headers'] ?? []) + ->content(...$properties['content'] ?? []) + ->links(...$properties['links'] ?? []); + } } diff --git a/src/Objects/Schema.php b/src/Objects/Schema.php index 0fd89da..7439c93 100644 --- a/src/Objects/Schema.php +++ b/src/Objects/Schema.php @@ -352,7 +352,7 @@ public function type(?string $type): self * @param \GoldSpecDigital\ObjectOrientedOAS\Contracts\SchemaContract $items * @return static */ - public function items(SchemaContract $items): self + public function items(?SchemaContract $items): self { $instance = clone $this; @@ -783,4 +783,40 @@ protected function generate(): array 'deprecated' => $this->deprecated, ]); } + + public static function __set_state(array $properties) + { + return parent::__set_state($properties) + ->title($properties['title']) + ->description($properties['description']) + ->enum(...($properties['enum'] ?? [])) + ->default($properties['default']) + ->format($properties['format']) + ->type($properties['type']) + ->items($properties['items']) + ->maxItems($properties['maxItems']) + ->minItems($properties['minItems']) + ->uniqueItems($properties['uniqueItems']) + ->pattern($properties['pattern']) + ->maxLength($properties['maxLength']) + ->minLength($properties['minLength']) + ->maximum($properties['maximum']) + ->exclusiveMaximum($properties['exclusiveMaximum']) + ->minimum($properties['minimum']) + ->exclusiveMinimum($properties['exclusiveMinimum']) + ->multipleOf($properties['multipleOf']) + ->required(...($properties['required'] ?? [])) + ->properties(...($properties['properties'] ?? [])) + ->additionalProperties($properties['additionalProperties']) + ->maxProperties($properties['maxProperties']) + ->minProperties($properties['minProperties']) + ->nullable($properties['nullable']) + ->discriminator($properties['discriminator']) + ->readOnly($properties['readOnly']) + ->writeOnly($properties['writeOnly']) + ->xml($properties['xml']) + ->externalDocs($properties['externalDocs']) + ->example($properties['example']) + ->deprecated($properties['deprecated']); + } } diff --git a/src/Objects/SchemaComposition.php b/src/Objects/SchemaComposition.php index 8d62a76..d414dc2 100644 --- a/src/Objects/SchemaComposition.php +++ b/src/Objects/SchemaComposition.php @@ -44,4 +44,10 @@ protected function generate(): array $this->compositionType() => $this->schemas, ]); } + + public static function __set_state(array $properties) + { + return parent::__set_state($properties) + ->schemas(...($properties['schemas'] ?? [])); + } } diff --git a/src/Objects/SecurityRequirement.php b/src/Objects/SecurityRequirement.php index e3da7f3..3d7de71 100644 --- a/src/Objects/SecurityRequirement.php +++ b/src/Objects/SecurityRequirement.php @@ -74,4 +74,11 @@ protected function generate(): array $this->securityScheme => $this->scopes ?? [], ]); } + + public static function __set_state(array $properties) + { + return parent::__set_state($properties) + ->securityScheme($properties['securityScheme']) + ->scopes(...($properties['scopes'] ?? [])); + } } diff --git a/src/Objects/SecurityScheme.php b/src/Objects/SecurityScheme.php index 0226b94..8199309 100644 --- a/src/Objects/SecurityScheme.php +++ b/src/Objects/SecurityScheme.php @@ -201,4 +201,17 @@ protected function generate(): array 'openIdConnectUrl' => $this->openIdConnectUrl, ]); } + + public static function __set_state(array $properties): self + { + return parent::__set_state($properties) + ->type($properties['type']) + ->description($properties['description']) + ->name($properties['name']) + ->in($properties['in']) + ->scheme($properties['scheme']) + ->bearerFormat($properties['bearerFormat']) + ->flows(...($properties['flows'] ?? [])) + ->openIdConnectUrl($properties['openIdConnectUrl']); + } } diff --git a/src/Objects/Server.php b/src/Objects/Server.php index 18b0503..769c799 100644 --- a/src/Objects/Server.php +++ b/src/Objects/Server.php @@ -83,4 +83,12 @@ protected function generate(): array 'variables' => $variables ?: null, ]); } + + public static function __set_state(array $properties): self + { + return parent::__set_state($properties) + ->url($properties['url']) + ->description($properties['description']) + ->variables(...($properties['variables'] ?? [])); + } } diff --git a/src/Objects/ServerVariable.php b/src/Objects/ServerVariable.php index 7163284..1c0be86 100644 --- a/src/Objects/ServerVariable.php +++ b/src/Objects/ServerVariable.php @@ -78,4 +78,12 @@ protected function generate(): array 'description' => $this->description, ]); } + + public static function __set_state(array $properties): self + { + return parent::__set_state($properties) + ->enum($properties['enum']) + ->default($properties['default']) + ->description($properties['description']); + } } diff --git a/src/Objects/Tag.php b/src/Objects/Tag.php index 6b415d1..029745c 100644 --- a/src/Objects/Tag.php +++ b/src/Objects/Tag.php @@ -78,4 +78,12 @@ protected function generate(): array 'externalDocs' => $this->externalDocs, ]); } + + public static function __set_state(array $properties): self + { + return parent::__set_state($properties) + ->name($properties['name']) + ->description($properties['description']) + ->externalDocs($properties['externalDocs']); + } } diff --git a/src/Objects/Xml.php b/src/Objects/Xml.php index a6f741a..3d0ff5b 100644 --- a/src/Objects/Xml.php +++ b/src/Objects/Xml.php @@ -118,4 +118,14 @@ protected function generate(): array 'wrapped' => $this->wrapped, ]); } + + public static function __set_state(array $properties): self + { + return parent::__set_state($properties) + ->name($properties['name']) + ->namespace($properties['namespace']) + ->prefix($properties['prefix']) + ->attribute($properties['attribute']) + ->wrapped($properties['wrapped']); + } } diff --git a/src/OpenApi.php b/src/OpenApi.php index cedc15a..7304db0 100644 --- a/src/OpenApi.php +++ b/src/OpenApi.php @@ -222,4 +222,17 @@ protected function generate(): array 'externalDocs' => $this->externalDocs, ]); } + + public static function __set_state(array $properties) + { + return parent::__set_state($properties) + ->openapi($properties['openapi']) + ->info($properties['info']) + ->servers(...($properties['servers'] ?? [])) + ->paths(...($properties['paths'] ?? [])) + ->components($properties['components']) + ->security(...($properties['security'] ?? [])) + ->tags(...($properties['tags'] ?? [])) + ->externalDocs($properties['externalDocs']); + } } diff --git a/src/Utilities/Extensions.php b/src/Utilities/Extensions.php index c04cb17..6d3f2fc 100644 --- a/src/Utilities/Extensions.php +++ b/src/Utilities/Extensions.php @@ -105,4 +105,13 @@ protected function normalizeOffset($offset) return 'x-' . $offset; } + + public static function __set_state(array $properties): self + { + $obj = new self(); + + $obj->items = $properties['items']; + + return $obj; + } } diff --git a/tests/OpenApiTest.php b/tests/OpenApiTest.php index 94bb6e2..96cce26 100644 --- a/tests/OpenApiTest.php +++ b/tests/OpenApiTest.php @@ -29,6 +29,59 @@ class OpenApiTest extends TestCase /** @test */ public function all_properties_works_and_validation_passes() { + $openApi = $this->createSchema(); + + $exampleResponse = file_get_contents(realpath(__DIR__) . '/storage/example_response.json'); + + $this->assertEquals( + json_decode($exampleResponse, true), + $openApi->toArray() + ); + + $openApi->validate(); + } + + /** @test */ + public function set_state_passes_equality() + { + $openApi = $this->createSchema(); + + $imported = eval('return ' . var_export($openApi, true) . ';'); + + $this->assertEquals($openApi, $imported); + } + + /** @test */ + public function validate() + { + $exceptionThrown = false; + + try { + $openApi = OpenApi::create() + ->openapi('4.0.0') + ->info( + Info::create()->title('foo') + ) + ->paths( + PathItem::create() + ->route('/foo') + ->operations( + Operation::get() + ) + ); + + $openApi->validate(); + } + catch(ValidationException $exception) { + $exceptionThrown = true; + + $this->assertCount(3, $exception->getErrors()); + } + + $this->assertTrue($exceptionThrown); + } + + protected function createSchema(): OpenApi { // Create a tag. $tag = Tag::create() ->name('Audits') @@ -146,7 +199,7 @@ public function all_properties_works_and_validation_passes() ->description('GitHub Wiki'); // Create the main OpenAPI object composed off everything created above. - $openApi = OpenApi::create() + return OpenApi::create() ->openapi(OpenApi::OPENAPI_3_0_1) ->info($info) ->paths(...$paths) @@ -155,44 +208,5 @@ public function all_properties_works_and_validation_passes() ->security($security) ->tags($tag) ->externalDocs($externalDocs); - - $exampleResponse = file_get_contents(realpath(__DIR__) . '/storage/example_response.json'); - - $this->assertEquals( - json_decode($exampleResponse, true), - $openApi->toArray() - ); - - $openApi->validate(); - } - - /** @test */ - public function validate() - { - $exceptionThrown = false; - - try { - $openApi = OpenApi::create() - ->openapi('4.0.0') - ->info( - Info::create()->title('foo') - ) - ->paths( - PathItem::create() - ->route('/foo') - ->operations( - Operation::get() - ) - ); - - $openApi->validate(); - } - catch(ValidationException $exception) { - $exceptionThrown = true; - - $this->assertCount(3, $exception->getErrors()); - } - - $this->assertTrue($exceptionThrown); } } diff --git a/tests/PetStoreTest.php b/tests/PetStoreTest.php index fc0c254..2e80592 100644 --- a/tests/PetStoreTest.php +++ b/tests/PetStoreTest.php @@ -24,6 +24,27 @@ class PetStoreTest extends TestCase /** @test */ public function pet_store_example() { + $openApi = $this->createSchema(); + + $exampleResponse = file_get_contents(realpath(__DIR__) . '/storage/petstore_expanded.json'); + + $this->assertEquals( + json_decode($exampleResponse, true), + $openApi->toArray() + ); + } + + /** @test */ + public function set_state_passes_equality() + { + $openApi = $this->createSchema(); + + $imported = eval('return ' . var_export($openApi, true) . ';'); + + $this->assertEquals($openApi, $imported); + } + + protected function createSchema(): OpenApi { $contact = Contact::create() ->name('Swagger API Team') ->email('apiteam@swagger.io') @@ -167,18 +188,11 @@ public function pet_store_example() ->route('/pets/{id}') ->operations($findPetById, $deletePetById); - $openApi = OpenApi::create() + return OpenApi::create() ->openapi(OpenApi::OPENAPI_3_0_0) ->info($info) ->servers($server) ->paths($petRoot, $petNested) ->components($components); - - $exampleResponse = file_get_contents(realpath(__DIR__) . '/storage/petstore_expanded.json'); - - $this->assertEquals( - json_decode($exampleResponse, true), - $openApi->toArray() - ); } } diff --git a/tests/ReadmeTest.php b/tests/ReadmeTest.php index 7f353fb..2b38d01 100644 --- a/tests/ReadmeTest.php +++ b/tests/ReadmeTest.php @@ -19,52 +19,7 @@ class ReadmeTest extends TestCase /** @test */ public function the_readme_example() { - // Create a tag for all the user endpoints. - $usersTag = Tag::create() - ->name('Users') - ->description('All user related endpoints'); - - // Create the info section. - $info = Info::create() - ->title('API Specification') - ->version('v1') - ->description('For using the Example App API'); - - // Create the user schema. - $userSchema = Schema::object() - ->properties( - Schema::string('id')->format(Schema::FORMAT_UUID), - Schema::string('name'), - Schema::integer('age')->example(23), - Schema::string('created_at')->format(Schema::FORMAT_DATE_TIME) - ); - - // Create the user response. - $userResponse = Response::create() - ->statusCode(200) - ->description('OK') - ->content( - MediaType::json()->schema($userSchema) - ); - - // Create the operation for the route (i.e. GET, POST, etc.). - $showUser = Operation::get() - ->responses($userResponse) - ->tags($usersTag) - ->summary('Get an individual user') - ->operationId('users.show'); - - // Define the /users path along with the supported operations. - $usersPath = PathItem::create() - ->route('/users') - ->operations($showUser); - - // Create the main OpenAPI object composed off everything created above. - $openApi = OpenApi::create() - ->openapi(OpenApi::OPENAPI_3_0_1) - ->info($info) - ->paths($usersPath) - ->tags($usersTag); + $openApi = $this->createSchema(); $readmeExample = file_get_contents(realpath(__DIR__) . '/storage/readme_example.json'); @@ -74,6 +29,16 @@ public function the_readme_example() ); } + /** @test */ + public function set_state_passes_equality() + { + $openApi = $this->createSchema(); + + $imported = eval('return ' . var_export($openApi, true) . ';'); + + $this->assertEquals($openApi, $imported); + } + /** @test */ public function setting_and_unsetting_properties() { @@ -181,4 +146,53 @@ public function dollar_ref() ], ], $schema->toArray()); } + + protected function createSchema(): OpenApi { + // Create a tag for all the user endpoints. + $usersTag = Tag::create() + ->name('Users') + ->description('All user related endpoints'); + + // Create the info section. + $info = Info::create() + ->title('API Specification') + ->version('v1') + ->description('For using the Example App API'); + + // Create the user schema. + $userSchema = Schema::object() + ->properties( + Schema::string('id')->format(Schema::FORMAT_UUID), + Schema::string('name'), + Schema::integer('age')->example(23), + Schema::string('created_at')->format(Schema::FORMAT_DATE_TIME) + ); + + // Create the user response. + $userResponse = Response::create() + ->statusCode(200) + ->description('OK') + ->content( + MediaType::json()->schema($userSchema) + ); + + // Create the operation for the route (i.e. GET, POST, etc.). + $showUser = Operation::get() + ->responses($userResponse) + ->tags($usersTag) + ->summary('Get an individual user') + ->operationId('users.show'); + + // Define the /users path along with the supported operations. + $usersPath = PathItem::create() + ->route('/users') + ->operations($showUser); + + // Create the main OpenAPI object composed off everything created above. + return OpenApi::create() + ->openapi(OpenApi::OPENAPI_3_0_1) + ->info($info) + ->paths($usersPath) + ->tags($usersTag); + } }