Skip to content

6.17.0

Latest

Choose a tag to compare

@DerManoMann DerManoMann released this 19 Oct 02:55
3e4aafd

Spec pipeline

One attribute for several targets

Every spec attribute takes fan:. With fan: OA\Fan::All, an attribute that more than one attribute could hold goes into each of them, as a copy. Without it, that is an error naming the candidates. (#2276)

#[OA\Operation\Put(path: '/pets/{id}')]
#[OA\Operation\Delete(path: '/pets/{id}')]
#[OA\Response(response: 404, description: 'Not found', fan: OA\Fan::All)]
public function change(
    #[OA\Parameter\Path(name: 'id', fan: OA\Fan::All)]
    int $id,
) {}

Both operations get the 404 response and the id parameter. The same works for a Header next to several responses. The targets have to be of one type: a MediaType next to both a Response and a RequestBody stays an error.

One operation for several methods

OA\Operation takes methods:, and is split into one operation per method during assembly. While it is the only operation on its method, everything that nests into it goes to each method without a fan. (#2280)

#[OA\Operation(path: '/pets/{id}', operationId: '{method}Pet', methods: [OA\HttpMethod::Put, OA\HttpMethod::Patch])]
#[OA\Response(response: 204, description: 'Updated')]
public function update(
    #[OA\Parameter\Path(name: 'id')]
    int $id,
) {}

{method} in an explicit operationId is replaced by each operation's method, here putPet and patchPet. An operationId without it is dropped on several methods, with a warning, and each operation gets a generated one. method and methods together are an error.

The split is the new default translator Assembler\OperationMethodsTranslator. A custom translator that creates methods: operations has to run before it, so insert() it ahead of that class rather than add() it.

A schema as content

content: on Response and RequestBody takes a bare schema, the payload of one media type. nelmio's content: new Model(...) has worked this way for years. (#2285)

#[OA\Response(response: 200, description: 'The pet', content: new OA\Schema\Ref(Pet::class))]

The new DefaultMediaType augmenter gives every media type without a type application/json, or whatever defaultMediaType.mediaType is set to. An explicit type is never changed, so a single response can still name its own. Parameter and Header keep content: as media types, since their own schema: means something else.

Smaller changes

  • A resolver implementing LoggerAwareInterface is given the logger set with Builder::setLogger(). So is a translator. (#2281, #2280)
  • An operation inherited by several child classes, the responses and security requirements a PathItem pushes into its operations, and a PathItem repeated per path, each get their own copy. Before, they shared children, so an augmenter changing one changed them all. No built-in augmenter does that, so the default output is the same. (#2278)

Rector set

  • ComponentsHolderRector takes ROUTE_ATTRIBUTES, a list of route attribute classes, empty by default. A method carrying one does not make its class a holder, so a #[Response] decorating a framework route is left as it is. The migration guide shows the set configured with Symfony's Route from a project's own rector.php. (#2282)

Output changes

An attribute several attributes could hold

This changes spec output. An attribute on a PHP parameter that matched more than one operation went into the first one, without a warning. It is now an error, and the class is left out with a warning, like an ambiguous sibling already was. Add fan: OA\Fan::All to put it into each, or nest it where it belongs. (#2276)

Schema\Items wherever it is nested

This changes spec output. A Schema\Items was only expanded into an array schema as the schema of a media type, parameter, header or property. Inside oneOf, anyOf, allOf, not, prefixItems or additionalProperties, or as a class-level component, it compiled as its item schema. It is now an array everywhere, except directly in the items of a plain schema, where it stays the item schema, as the rector set writes it. A class-level Schema\Items keeps its component. (#2279)

{method} in an explicit operationId

This changes spec output. {method} in an explicit operationId is now replaced by the operation's method, on every operation. An id that contained it literally changes. (#2280)

Media types without a type

This changes spec output for a Specification compiled without the DefaultMediaType augmenter, such as a custom pipeline. A media type without a type was compiled as application/json; it is now left out with a warning. The default pipeline is not affected. A media type repeated in one content list now warns, and the last one is still kept. (#2285)

Documentation

  • Mergers have a reference page of their own: the default and opt-in mergers, what makes two attributes the same one, and the Merge\Mode cases. (#2284)
  • The api example shares a header through fan:, the guide's fan: and methods: examples run as tests, and the migration guide offers both for headers and responses shared by several targets. (#2283)

What's Changed

  • feat(Spec): let a nestable attribute fan out to every matching target by @DerManoMann in #2276
  • test(Spec): mix explicit and shortcut spellings in examples and fixtures by @DerManoMann in #2277
  • fix(Augmenter): give each holder its own copy of shared children by @DerManoMann in #2278
  • feat(Spec): let one operation declare several HTTP methods by @DerManoMann in #2280
  • feat(Resolver): give LoggerAware resolvers the resolver's logger by @DerManoMann in #2281
  • fix(Augmenter): expand a Schema\Items wherever it is nested by @DerManoMann in #2279
  • docs(Merge): add a mergers reference page by @DerManoMann in #2284
  • docs(Guide): show fan: and methods: in an example and in verified snippets by @DerManoMann in #2283
  • feat(Rector): let ComponentsHolderRector skip methods carrying a route attribute by @DerManoMann in #2282
  • feat(Spec): let content: take a bare Schema on Response and RequestBody by @DerManoMann in #2285

Full Changelog: 6.16.0...6.17.0