PHPackages                             selency/openapi - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. selency/openapi

ActiveLibrary[API Development](/categories/api)

selency/openapi
===============

Provides a user-friendly, object-oriented library to build OpenAPI specifications using PHP.

v0.1.0(3y ago)275.3k1[1 issues](https://github.com/selency/openapi/issues)[1 PRs](https://github.com/selency/openapi/pulls)MITPHPPHP &gt;=8.1

Since Mar 23Pushed 2y ago4 watchersCompare

[ Source](https://github.com/selency/openapi)[ Packagist](https://packagist.org/packages/selency/openapi)[ Docs](https://selency.fr)[ RSS](/packages/selency-openapi/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (6)Versions (2)Used By (0)

Selency OpenAPI
===============

[](#selency-openapi)

The OpenApi component provides a user-friendly, object-oriented API to build OpenAPI specifications using PHP.

Sponsor
-------

[](#sponsor)

[Selency](https://www.selency.fr) is a team of 80 people, each more committed than the last to promoting second-hand goods and doing something positive for our planet. Open-Source is perfectly aligned with our values, leading us to contribute back to the Symfony ecosystem through a series of components.

We're always looking for talented people, [join us](https://www.welcometothejungle.com/fr/companies/selency)!

Usage
-----

[](#usage)

```
composer require selency/openapi

```

Selency OpenApi implements the OpenApi standard in its version 3.1. It allows to build documentations using PHP objects, giving more flexibility and reusability to OpenApi definitions. All features of OpenApi 3.1 are supported.

### Writing documentation

[](#writing-documentation)

The OpenApi component provides object-oriented PHP tools to build the documentation definition:

```
// openapi/Documentation.php

use Selency\OpenApi\Documentation\AbstractDocumentation;

class Documentation extends AbstractDocumentation
{
    public function getIdentifier(): string
    {
        return 'myapi';
    }

    public function getVersion(): string
    {
        return '1.3.4';
    }

    public function configure(DocumentationConfigurator $doc): void
    {
        $doc->info($this->openApi->info()
            ->title('Monolith API')
            ->description(file_get_contents(__DIR__.'/Resources/info_description.md'))
            ->contact(name: 'API support', url: 'https://symfony.com', email: 'contact@symfony.com')
            ->specificationExtension('x-logo', [
                'url' => 'https://symfony.com/logos/symfony_black_02.png',
                'altText' => 'Symfony logo',
            ])
            ->license('MIT')
        );

        $doc->externalDocs(url: 'https://github.com/symfony/openapi', description: 'OpenApi component');

        $doc->server($this->openApi->server('https://api.symfony.local')->description('Local'))
            ->server($this->openApi->server('https://api.symfony-staging.com')->description('Staging'))
            ->server($this->openApi->server('https://api.symfony.com')->description('Prod'));

        $doc->securityRequirement(self::REF_SECURITY_USER_JWT);

        $doc->path('/health', $this->openApi->pathItem()
            ->get($this->openApi->operation()
                ->tag('Health')
                ->operationId('app.health.check')
                ->summary('Health check')
                ->description('Check the API is up and available.')
                ->securityRequirement(null)
                ->responses($this->openApi->responses()
                    ->response('200', $this->openApi->response()
                        ->description('When the API is up and available.')
                        ->content('application/json', $this->openApi->schema()
                            ->property('name', $this->openApi->schema()->type('string')->description('Name for this API')->example('Selency API'))
                            ->property('env', $this->openApi->schema()->type('string')->description('Current environment of this instance of the API')->example('prod'))
                        )
                    )
                    ->response('500', $this->openApi->response()->description('When the API is unavailable due to a backend problem.'))
                )
            )
        );

        // ...
    }
}

// Build a read-only model representing the documentation
$compiler = new DocumentationCompiler();
$openApiDefinition = $compiler->compile($doc);

// Compile it as YAML or JSON for usage in other tools
$openApiYaml = (new Dumper\YamlDumper())->dump($openApiDefinition);
$openApiJson = (new Dumper\JsonDumper())->dump($openApiDefinition);
```

### Splitting documentations in multiple files

[](#splitting-documentations-in-multiple-files)

The component provides a concept of Partial documentations to allow splitting the documentation in multiple files for readability:

```
// HealthDocumentation.php
use Selency\OpenApi\Documentation\PartialDocumentationInterface;

#[AutoconfigureTag('app.partial_documentation')]
class HealthDocumentation implements PartialDocumentationInterface
{
    public function __construct(private OpenApiBuilderInterface $openApi)
    {
    }

    public function configure(DocumentationConfigurator $doc): void
    {
        $doc->path('/health', $this->openApi->pathItem()
            ->get($this->openApi->operation()
                ->tag('Health')
                ->operationId('app.health.check')
                ->summary('Health check')
                ->description('Check the API is up and available. Mostly used by the infrastructure to check for readiness.')
                ->securityRequirement(null)
                ->responses($this->openApi->responses()
                    ->response('200', $this->openApi->response()
                        ->description('When the API is up and available.')
                        ->content('application/json', $this->openApi->schema()
                            ->property('name', $this->openApi->schema()->type('string')->description('Name for this API')->example('Selency API'))
                            ->property('env', $this->openApi->schema()->type('string')->description('Current environment of this instance of the API')->example('prod'))
                        )
                    )
                    ->response('500', $this->openApi->response()->description('When the API is unavailable due to a backend problem.'))
                )
            )
        );
    }
}

// Documentation.php
class Documentation extends AbstractDocumentation
{
    private iterable $partialsDocs;

    public function __construct(
        private Builder\OpenApiBuilder $openApi,
        #[TaggedIterator(tag: 'app.partial_documentation')] iterable $partialsDocs,
    ) {
        $this->partialsDocs = $partialsDocs;
    }

    public function getIdentifier(): string
    {
        return 'myapi';
    }

    public function getVersion(): string
    {
        return '1.3.4';
    }

    public function configure(DocumentationConfigurator $doc): void
    {
        $doc->info($this->openApi->info()
            ->title('Monolith API')
            ->description(file_get_contents(__DIR__.'/Resources/info_description.md'))
            ->contact(name: 'API support', url: 'https://symfony.com', email: 'contact@symfony.com')
            ->specificationExtension('x-logo', [
                'url' => 'https://symfony.com/logos/symfony_black_02.png',
                'altText' => 'Symfony logo',
            ])
            ->license('MIT')
        );

        // ...

        // Apply partial documentations
        foreach ($this->partialsDocs as $partialsDoc) {
            $partialsDoc->configure($doc);
        }
    }
}
```

### Store documentation close to your application code

[](#store-documentation-close-to-your-application-code)

The OpenApi component provides two interfaces to help maintaining documentation by storing it close to your code:

- `SelfDescribingSchemaInterface` can be implemented by classes describing a schema (request, response, payloads, ...) ;
- `SelfDescribingQueryParametersInterface` can be implemented by classes describing a list of query parameters ;

These interfaces are especially useful when using objects to handle inputs and outputs of your API:

```
class AuthRegisterPayload implements SelfDescribingSchemaInterface
{
    #[Assert\Email(mode: Email::VALIDATION_MODE_STRICT)]
    #[Assert\NotBlank]
    public $email;

    #[Assert\Type(type: 'string')]
    #[Assert\NotBlank]
    public $firstName;

    #[Assert\Type(type: 'string')]
    #[Assert\NotBlank]
    public $lastName;

    #[Assert\Type(type: 'string')]
    #[Assert\NotBlank]
    public $password;

    public static function describeSchema(SchemaConfigurator $schema, OpenApiBuilderInterface $openApi): void
    {
        $schema
            ->title('AuthRegister')
            ->required(['email', 'firstName', 'lastName', 'password'])
            ->property('email', $openApi->schema()
                ->type('string')
                ->description('User\'s email')
                ->example('john.doe@domain.com')
            )
            ->property('firstName', $openApi->schema()
                ->type('string')
                ->description('User\'s first name')
                ->example('John')
            )
            ->property('lastName', $openApi->schema()
                ->type('string')
                ->description('User\'s last name')
                ->example('Doe')
            )
            ->property('password', $openApi->schema()
                ->type('string')
                ->description('User\'s plaintext password')
            )
        ;
    }
}
```

You can then load these self-describing schemas/query params classes by providing the dedicated loader during compilation:

```
// Build a read-only model representing the documentation
$compiler = new DocumentationCompiler([
    new Selency\OpenApi\Loader\SelfDescribingSchemaLoader([
        AuthRegisterPayload::class,
    ])
]);

$openApiDefinition = $compiler->compile($doc);
```

> **Note**: in a Symfony application, SelfDescribingSchemaInterface and SelfDescribingQueryParametersInterface class are automatically added to the compiler, you don't need to do anything.

And use them in your definitions:

```
class Documentation extends AbstractDocumentation
{
    // ...

    public function configure(DocumentationConfigurator $doc): void
    {
        // ...

        $doc->path('/auth/register', $this->openApi->pathItem()
            ->post($this->openApi->operation()
                ->tag('Auth')
                ->operationId('app.auth.register')
                ->summary('Auth registration')
                ->description('Register as a user.')
                ->securityRequirement(null)
                ->requestBody($this->openApi->requestBody()
                    ->content('application/json', AuthRegisterPayload::class)
                )
                ->responses($this->openApi->responses()
                    ->response('200', $this->openApi->response()
                        ->content('application/json', AuthRegisterOutput::class)
                    )
                )
            )
        );

        // ...
    }
}
```

###  Health Score

28

—

LowBetter than 54% of packages

Maintenance19

Infrequent updates — may be unmaintained

Popularity27

Limited adoption so far

Community12

Small or concentrated contributor base

Maturity43

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 80% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

1152d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/66aab89d1577faa8a5e1cc85f7ff49b08bb54087bf5577d8ffc205f2220874bd?d=identicon)[Selency](/maintainers/Selency)

---

Top Contributors

[![tgalopin](https://avatars.githubusercontent.com/u/1651494?v=4)](https://github.com/tgalopin "tgalopin (4 commits)")[![JulienRAVIA](https://avatars.githubusercontent.com/u/8202241?v=4)](https://github.com/JulienRAVIA "JulienRAVIA (1 commits)")

---

Tags

apidocumentationspecificationopenapi

###  Code Quality

TestsPHPUnit

Static AnalysisPsalm

Type Coverage Yes

### Embed Badge

![Health badge](/badges/selency-openapi/health.svg)

```
[![Health](https://phpackages.com/badges/selency-openapi/health.svg)](https://phpackages.com/packages/selency-openapi)
```

###  Alternatives

[swagger-api/swagger-ui

 Swagger UI is a collection of HTML, Javascript, and CSS assets that dynamically generate beautiful documentation from a Swagger-compliant API.

28.7k45.4M99](/packages/swagger-api-swagger-ui)[darkaonline/l5-swagger

OpenApi or Swagger integration to Laravel

2.9k34.0M112](/packages/darkaonline-l5-swagger)[darkaonline/swagger-lume

OpenApi or Swagger integration to Lumen

3372.3M3](/packages/darkaonline-swagger-lume)[juststeveking/laravel-redoc

A simple API documentation package for Laravel using OpenAPI and Redoc

92289.9k1](/packages/juststeveking-laravel-redoc)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
