A framework-independent PHP library for parsing OpenAPI documents into one immutable, typed model.
OpenAPI 2.0, 3.0, and 3.1 documents all produce the same Utopia\OpenAPI\Specification object. Consumers can work with metadata, operations, schemas, requests, responses, and security without handling each source format separately.
| Source format | Supported versions | Version enum |
|---|---|---|
| OpenAPI (Swagger) 2 | 2.0 |
Version::V2 |
| OpenAPI 3.0 | 3.0 and all 3.0.x patch releases |
Version::V3_0 |
| OpenAPI 3.1 | 3.1 and all 3.1.x patch releases |
Version::V3_1 |
The complete source version remains available through Specification::$sourceVersion. For example, an openapi: 3.1.1 document has Version::V3_1 as its semantic version and 3.1.1 as its source version.
Swagger 1.x is not supported.
- PHP 8.5 or newer
ext-json
Install the package with Composer:
composer require utopia-php/openapiPass JSON content directly to the parser:
use Utopia\OpenAPI\Parser;
$json = file_get_contents('openapi.json');
$specification = Parser::parse($json);Decoded associative arrays are also accepted:
$specification = Parser::parse([
'openapi' => '3.1.0',
'info' => [
'title' => 'Example API',
'version' => '1.0.0',
],
'paths' => [],
]);The parser detects the format from swagger: 2.0 or openapi: 3.x.x.
Supply a Version when the caller expects a particular OpenAPI version:
use Utopia\OpenAPI\Parser;
use Utopia\OpenAPI\Version;
$specification = Parser::parse(
input: $json,
version: Version::V3_1,
);Parsing fails with InvalidSpecification if the expected version and declared document version differ.
An instance API is available as well:
$parser = new Parser();
$specification = $parser->read($json);Every supported source format produces a Utopia\OpenAPI\Specification containing:
- OpenAPI and API metadata
- Servers and server variables
- Tags
- Paths and operations
- Component schemas
- Security schemes and requirements
- Vendor extensions
use Utopia\OpenAPI\Model\HttpMethod;
foreach ($specification->paths as $path => $pathItem) {
foreach ($pathItem->operations as $operation) {
echo strtoupper($operation->method->value);
echo ' ' . $operation->path . PHP_EOL;
}
}
$getPet = $specification
->paths['/pets/{id}']
->operation(HttpMethod::GET);All operations can be retrieved as one ordered list:
$operations = $specification->operations();Operations can also be selected by an OpenAPI tag:
$petOperations = $specification->operationsByTag('pets');The library models OpenAPI tags as tags. It does not assign SDK service or platform semantics to them.
Schemas are represented by typed classes under Utopia\OpenAPI\Model\Schema:
AnySchemaandNeverSchemaStringSchemaIntegerSchemaNumberSchemaBooleanSchemaObjectSchemaArraySchemaReferenceSchemaCompositeSchema
The model preserves:
- Formats, defaults, enums, examples, and common constraints
- Object properties and required property names
- All three
additionalPropertiesstates: forbidden, unconstrained, or schema-constrained oneOf,anyOf,allOf, andnot- Discriminators and discriminator mappings
- OpenAPI 3.0
nullable: true - OpenAPI 3.1 null types such as
type: [string, "null"] - OpenAPI 3.1 boolean schemas
Schema references remain references rather than being recursively expanded:
use Utopia\OpenAPI\Model\Schema\ReferenceSchema;
$schema = $specification->schemas['Pet'];
if ($schema instanceof ReferenceSchema) {
echo $schema->reference;
}This makes valid recursive schemas safe to parse.
Path-level parameters are inherited by operations. An operation-level parameter with the same case-sensitive name and in value replaces the inherited parameter.
OpenAPI 3.x request bodies and OpenAPI 2.0 body parameters both produce RequestBody objects. OpenAPI 2.0 form-data parameters are normalized into request content with object properties and encoding metadata.
Responses remain indexed by their original status code or default key. Response order is preserved.
OpenAPI 2.0 produces values and OpenAPI 3.x response content both produce MediaType objects. The same normalization applies to OpenAPI 2.0 consumes and request content.
Security alternatives retain OpenAPI's AND/OR semantics. This document:
security:
- Project: []
Session: []
- Project: []
JWT: []is represented as two SecurityRequirement objects and means:
(Project AND Session) OR (Project AND JWT)
Security inheritance is also preserved:
- A missing operation
securityinherits root security. - An explicit
security: []disables inherited security. - An empty requirement object represents anonymous access as an alternative.
Supported security scheme types include API keys, HTTP basic and bearer authentication, OAuth 2 flows, OpenID Connect, and OpenAPI 3.1 mutual TLS.
Fields whose names begin with x- are retained in each extensible model's extensions map:
$owner = $specification->info->extensions['x-owner'] ?? null;Extensions are opaque. The parser does not interpret x-appwrite or any other vendor-specific behavior.
OpenAPI 2.0 documents are read directly; they are not converted into an intermediate OpenAPI 3 document.
| OpenAPI 2.0 field | Canonical model |
|---|---|
host, basePath, schemes |
Server objects |
definitions |
Specification::$schemas |
| Body parameters | RequestBody |
| Form-data parameters | Request content and encodings |
consumes |
Request media types |
produces |
Response media types |
Response schema |
Response media schema |
securityDefinitions |
Security schemes |
Root and operation security |
Security requirements |
Global and operation-level consumes, produces, parameters, and security follow their standard inheritance and override rules.
Local references use RFC 6901 JSON Pointer syntax:
#/components/schemas/Pet
#/definitions/Pet
Escaped pointer tokens are supported:
~1represents/~0represents~
Local non-schema references needed to build typed objects are resolved with cycle detection. Schema references intentionally remain ReferenceSchema objects so recursive schema graphs are not expanded.
External file and URL references are not resolved. The parser never performs implicit filesystem or network access.
All public exceptions implement Utopia\OpenAPI\Exception\OpenAPIException:
ParseException— malformed JSON or another basic parsing failureInvalidSpecification— a document cannot produce a coherent typed modelUnsupportedVersion— the declared OpenAPI version is unsupportedReferenceNotFound— a required local reference does not existCircularReference— an invalid non-schema reference cycle was encountered
use Utopia\OpenAPI\Exception\OpenAPIException;
use Utopia\OpenAPI\Parser;
try {
$specification = Parser::parse($json);
} catch (OpenAPIException $exception) {
echo $exception->getMessage();
}The parser validates structure required to construct the model. It is not a complete OpenAPI conformance validator.
The core parser supports JSON strings and decoded PHP arrays. The following capabilities are intentionally outside its current scope:
- YAML parsing
- External reference resolution
- Implicit file or network access
- Complete OpenAPI conformance validation
- Serialization or textual round trips
- Callbacks, links, and OpenAPI 3.1 webhooks
- Interpretation of vendor extensions
- Swagger 1.x
A missing operationId is currently accepted and represented as an empty string.
Install dependencies and run the checks:
composer install
composer test
composer lint
composer format:check
composer rector:check
composer validate --strictRun composer format to apply Pint formatting and composer format:check to verify formatting without changing files. Run composer rector to apply automated refactoring and composer rector:check to check for suggested changes without modifying files. composer check runs syntax, formatting, Rector, and PHPUnit checks together.
GitHub Actions run PHPUnit, Composer validation, PHP syntax checks, Pint, and Rector for pull requests and pushes to main.
The test suite covers version handling, metadata, operations, parameter inheritance, requests, responses, schemas, recursive references, security semantics, OpenAPI 2.0 normalization, and JSON Pointer escaping.
MIT. See LICENSE.