Search by

radebatz / openapi-json-schema

DerManoMann

Describes classes without OpenAPI attributes in the document swagger-php builds, using the schemas symfony/json-schema generates from PropertyInfo, the serializer and validator constraints.

Package info

github.com/DerManoMann/openapi-json-schema

pkg:composer/radebatz/openapi-json-schema

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

0.1.0 2026-11-01 07:54 UTC

This package is auto-updated.

Last update: 2026-11-03 03:28:10 UTC


README

Build Status Coverage Status License: MIT

Introduction

A request or response often uses a class that has no OpenAPI attributes: a DTO, an entity, a class from another package. swagger-php can only describe a class through its attributes, so the class has to be annotated or the reference stays unresolved.

openapi-json-schema describes such a class with the schema symfony/json-schema generates for it. That schema comes from what Symfony already knows about the class: property types and docblocks through PropertyInfo, and with symfony/serializer and symfony/validator installed, serializer groups, name converters, discriminator maps and validator constraints.

symfony/json-schema is experimental. It ships with Symfony 8.2 and has no backwards compatibility promise yet. This package follows it and is experimental too. Once the component is stable, this package might move into swagger-php as an optional part.

Installation

composer require radebatz/openapi-json-schema

The package requires swagger-php 7. Until symfony/json-schema has a stable release, the project needs "minimum-stability": "dev" and "prefer-stable": true in its composer.json.

Usage

JsonSchemaResolver is a swagger-php resolver. Add it after swagger-php's own:

use OpenApi\Builder;
use OpenApi\Builder\Mode;
use OpenApi\Resolver;
use OpenApi\Utils\TypedList;
use Radebatz\OpenApi\JsonSchema\JsonSchemaResolver;

$result = (new Builder())
    ->setMode(Mode::SPEC)
    ->addSource('src')
    ->withResolver(fn (Resolver $resolver) => $resolver->withResolvers(
        fn (TypedList $resolvers) => $resolvers->add(new JsonSchemaResolver()),
    ))
    ->build();

A class referenced by its name, for example new OA\Schema(ref: Order::class), is then described like this:

  • A class with attributes is described by its attributes. swagger-php's own resolver runs first, and this one only sees what that left unresolved.
  • A class without attributes becomes a component with the schema Symfony generates.
  • The classes it references are resolved the same way. Each is referenced by its name, so it gets its own component, from its attributes where it has them.
  • swagger-php names the components. The names Symfony picks for its definitions are not used.
  • PHP's own classes are not components. Symfony describes a DateTimeImmutable inline where it is used.
  • A generic class is described once. Envelope<string> and Envelope<int> both reference the same Envelope component, and a template type like T allows any value.

Direction

By default one schema describes a class for both requests and responses, and marks a property that can only be read or only be written with readOnly or writeOnly. To describe classes for one direction only, pass it to the resolver:

use Symfony\Component\JsonSchema\Direction;

new JsonSchemaResolver(Direction::Output);

Serializer and validator

symfony/json-schema uses the serializer and the validator when they are installed. Nothing needs setting up here. With symfony/serializer, a schema describes what the serializer writes and reads:

  • A #[SerializedName] renames the property.
  • A #[DiscriminatorMap] becomes an anyOf of the mapped classes, each requiring the type property.

To describe only the properties of some serializer groups, pass them to the resolver:

new JsonSchemaResolver(groups: ['read']);

The groups apply to every class in the document. A property in none of them is left out, as the serializer leaves it out.

With symfony/validator installed, constraints become keywords: Length becomes minLength and maxLength, Range becomes minimum and maximum, and NotBlank makes the property required.

A discriminator map gives a cycle for now. Each mapped class extends the base class, so swagger-php adds the base class's component to the mapped class's allOf. The base class's component is the anyOf of the mapped classes, so the two reference each other. This needs a change in swagger-php.

License

The openapi-json-schema project is released under the MIT license.