PHPackages                             letsdrink/ouzo-open-api - 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. letsdrink/ouzo-open-api

ActiveLibrary[API Development](/categories/api)

letsdrink/ouzo-open-api
=======================

022.0k↓13%1[1 PRs](https://github.com/letsdrink/ouzo-open-api/pulls)PHPCI passing

Since Jun 20Pushed 2mo ago11 watchersCompare

[ Source](https://github.com/letsdrink/ouzo-open-api)[ Packagist](https://packagist.org/packages/letsdrink/ouzo-open-api)[ RSS](/packages/letsdrink-ouzo-open-api/feed)WikiDiscussions master Synced 2d ago

READMEChangelogDependenciesVersions (6)Used By (0)

Ouzo OpenAPI
============

[](#ouzo-openapi)

Generate an [OpenAPI 3.0.1](https://github.com/OAI/OpenAPI-Specification/blob/3.0.1/versions/3.0.1.md) specification directly from an [Ouzo framework](https://github.com/letsdrink/ouzo) application's routing table — no hand-written annotations required.

What it does
------------

[](#what-it-does)

Given a list of Ouzo `RouteRule`s, the library reflects on each controller method and produces a fully populated `OpenApi` document:

- **Paths &amp; operations** are derived from your routes (HTTP method + URI + controller@action).
- **Path &amp; query parameters** are read from method arguments (`:id` segments become `path` parameters; remaining scalars become `query` parameters).
- **Request bodies** are read from object-typed method arguments.
- **Responses** are read from method return types — including `void`, scalars, nullables, arrays of scalars/objects, and PHPDoc-typed arrays (`@return Tag[]`).
- **Component schemas** are collected automatically by walking class properties recursively, with cycle protection.
- **Polymorphism** via Symfony's `#[DiscriminatorMap]` is rendered as `oneOf` + discriminator mapping, with concrete classes emitted as `allOf` children.
- **Backed enums** (`int` / `string`) are emitted as enum schemas with the correct backing type.

The result is a plain object graph you can serialize to JSON or YAML with Symfony Serializer.

Requirements
------------

[](#requirements)

- PHP **&gt;= 8.4**
- `letsdrink/ouzo`
- `symfony/serializer`
- `phpdocumentor/reflection-docblock` (used to read PHPDoc array element types)

Installation
------------

[](#installation)

```
composer require letsdrink/ouzo-open-api
```

Usage
-----

[](#usage)

### 1. Provide your routes

[](#1-provide-your-routes)

Implement [`RouteRulesProvider`](src/OpenApi/RouteRulesProvider.php) so the library knows which routes to document. Typically you return whatever Ouzo has already registered in its router.

```
use Ouzo\OpenApi\RouteRulesProvider;
use Ouzo\Routing\Route;
use Ouzo\Routing\RouteRule;

class AppRouteRulesProvider implements RouteRulesProvider
{
    /** @return RouteRule[] */
    public function get(): array
    {
        return Route::getRoutes();
    }
}
```

### 2. (Optional) Customize the document

[](#2-optional-customize-the-document)

The generator does not populate `info` or `servers` — supply them via an [`OpenApiCustomizer`](src/OpenApi/Customizer/OpenApiCustomizer.php). Multiple customizers may be registered; each receives the final `OpenApi` instance and can mutate it.

```
use Ouzo\OpenApi\Customizer\OpenApiCustomizer;
use Ouzo\OpenApi\Model\Info\Info;
use Ouzo\OpenApi\Model\OpenApi;
use Ouzo\OpenApi\Model\Servers\Server;

class AppInfoCustomizer implements OpenApiCustomizer
{
    public function customize(OpenApi $openApi): void
    {
        $openApi
            ->setInfo(new Info()
                ->setTitle('My API')
                ->setDescription('Public API')
                ->setVersion('1.0.0'))
            ->setServers([new Server()->setUrl('https://api.example.com')]);
    }
}
```

### 3. Generate the spec

[](#3-generate-the-spec)

`OpenApiService` is wired through Ouzo's DI container (see `DefaultOpenApiModule`):

```
$openApi = $injector->getInstance(OpenApiService::class)->create();

// Serialize with symfony/serializer to JSON or YAML
echo $serializer->serialize($openApi, 'json');
```

Annotating your code
--------------------

[](#annotating-your-code)

The library favors convention — most types resolve from PHP reflection and PHPDoc alone — but two attributes give you fine-grained control.

### `#[Hidden]` — exclude routes from the spec

[](#hidden--exclude-routes-from-the-spec)

Apply on a controller class (hides every action) or on a single method.

```
use Ouzo\OpenApi\Attributes\Hidden;

class InternalController
{
    #[Hidden]
    public function debugDump(): void {}
}
```

### `#[Schema]` — mark properties as required / nullable

[](#schema--mark-properties-as-required--nullable)

```
use Ouzo\OpenApi\Attributes\Schema;

class CreateUser
{
    #[Schema(required: true)]
    public string $email;

    #[Schema(nullable: true)]
    public ?string $nickname;
}
```

### Arrays in PHPDoc

[](#arrays-in-phpdoc)

Element types for `array` are read from PHPDoc. Without it the property/return is emitted as a generic array.

```
/** @return Tag[] */
public function listTags(): array { /* ... */ }
```

### Polymorphism

[](#polymorphism)

Use Symfony's `#[DiscriminatorMap]` on the parent type and the library will emit a discriminator schema plus `oneOf`references where the parent type is used.

Architecture (brief)
--------------------

[](#architecture-brief)

`OpenApiService::create()` orchestrates three collaborators:

1. `PathsService` — turns each `RouteRule` into a `PathItem`/`Operation` (skipping `#[Hidden]` ones via `HiddenChecker`).
2. `ComponentsService` — drains the shared `SchemasRepository` (singleton) into `components.schemas`.
3. `OpenApiCustomizersRepository` — runs every registered `OpenApiCustomizer` over the final document.

Type resolution lives in `src/OpenApi/Util/Type/` and is the layer that bridges PHP reflection + PHPDoc to OpenAPI schemas.

Development
-----------

[](#development)

Tests are golden-file based: `OpenApiServiceTest` builds the full graph manually, serializes the resulting `OpenApi`, and compares against `tests/OpenApi/expected-openapi.json`. Fixtures under `tests/Fixtures/` (notably `SampleController`and `SampleClass`) are the canonical examples of every supported PHP type → OpenAPI shape.

```
# Inside a PHP 8.4+ environment with Composer
composer install
vendor/bin/phpunit tests
```

License
-------

[](#license)

MIT

###  Health Score

33

—

LowBetter than 72% of packages

Maintenance58

Moderate activity, may be stable

Popularity27

Limited adoption so far

Community16

Small or concentrated contributor base

Maturity28

Early-stage or recently created project

 Bus Factor1

Top contributor holds 93.2% 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.

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/2005054?v=4)[Piotr Olaszewski](/maintainers/piotrooo)[@piotrooo](https://github.com/piotrooo)

---

Top Contributors

[![piotrooo](https://avatars.githubusercontent.com/u/2005054?v=4)](https://github.com/piotrooo "piotrooo (41 commits)")[![bbankowski](https://avatars.githubusercontent.com/u/3840784?v=4)](https://github.com/bbankowski "bbankowski (1 commits)")[![Karpol](https://avatars.githubusercontent.com/u/16548691?v=4)](https://github.com/Karpol "Karpol (1 commits)")[![krzycho1997](https://avatars.githubusercontent.com/u/36961174?v=4)](https://github.com/krzycho1997 "krzycho1997 (1 commits)")

### Embed Badge

![Health badge](/badges/letsdrink-ouzo-open-api/health.svg)

```
[![Health](https://phpackages.com/badges/letsdrink-ouzo-open-api/health.svg)](https://phpackages.com/packages/letsdrink-ouzo-open-api)
```

###  Alternatives

[exsyst/swagger

A php library to manipulate Swagger specifications

35916.4M7](/packages/exsyst-swagger)[hubspot/api-client

Hubspot API client

24016.2M20](/packages/hubspot-api-client)[pocketmine/bedrock-protocol

An implementation of the Minecraft: Bedrock Edition protocol in PHP

172445.0k15](/packages/pocketmine-bedrock-protocol)[botman/driver-telegram

Telegram driver for BotMan

93459.5k6](/packages/botman-driver-telegram)

PHPackages © 2026

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