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
LoggerAwareInterfaceis given the logger set withBuilder::setLogger(). So is a translator. (#2281, #2280) - An operation inherited by several child classes, the responses and security requirements a
PathItempushes into its operations, and aPathItemrepeated 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
ComponentsHolderRectortakesROUTE_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'sRoutefrom a project's ownrector.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\Modecases. (#2284) - The
apiexample shares a header throughfan:, the guide'sfan:andmethods: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