-
-
Notifications
You must be signed in to change notification settings - Fork 108
Arazzo spec #443
Description
Description
Would you consider supporting Arazzo specification as an input source to generate API Platform operation stubs (State Processors, custom operations) ?
I'm exploring the idea of using the Arazzo Specification (OAI, v1.0.1) as an input source to generate custom operation stubs for API Platform — State Processors, Input DTOs, and #[Post]/#[Patch] attribute additions to existing entities.
I'd love to know if this fits the project's vision or should live in a separate package.
Related issue I noticed: #440
Context
Arazzo is the OAI specification for describing multi-step API workflows. Where OpenAPI describes what endpoints exist, Arazzo describes how a consumer orchestrates calls across those endpoints — including input/output chaining, success criteria, and error handling.
The key insight: an Arazzo file contains enough information to infer which API Platform custom operations are missing, and what their input shapes look like.
Proposed workflow
vendor/bin/schema generate user-onboarding.arazzo.yamlThe command would:
- Parse the Arazzo file
- Load the current OpenAPI spec generated by API Platform
- Diff: detect
operationIds referenced in Arazzo but absent from OpenAPI - Generate the corresponding PHP stubs
Example
Input: user-onboarding.arazzo.yaml
arazzo: 1.0.0
info:
title: User Onboarding
version: 1.0.0
sourceDescriptions:
- name: api
url: ./api/openapi.yaml
type: openapi
workflows:
- workflowId: user_onboarding
steps:
- stepId: register
operationId: api_users_post_collection
successCriteria:
- condition: $statusCode == 201
outputs:
userId: $response.body#/id
- stepId: verify_email
operationId: api_users_verify_post
parameters:
- name: id
in: path
value: $steps.register.outputs.userId
requestBody:
payload:
token: { type: string }
successCriteria:
- condition: $statusCode == 200
- stepId: complete_profile
operationId: api_users_complete_profile_patch
parameters:
- name: id
in: path
value: $steps.register.outputs.userId
requestBody:
payload:
bio: { type: string }
avatarUrl: { type: string, format: uri }
successCriteria:
- condition: $statusCode == 200Expected command output
✔ api_users_post_collection → already exists in OpenAPI, skipped
✘ api_users_verify_post → generating...
→ src/Dto/Input/UserVerifyInput.php
→ src/State/UserVerifyProcessor.php
→ (adds #[Post] operation to src/Entity/User.php)
✘ api_users_complete_profile_patch → generating...
→ src/Dto/Input/UserCompleteProfileInput.php
→ src/State/UserCompleteProfileProcessor.php
→ (adds #[Patch] operation to src/Entity/User.php)
2 operation stub(s) generated.
Generated: src/Dto/Input/UserVerifyInput.php
<?php
namespace App\Dto\Input;
final class UserVerifyInput
{
public string $token;
}Generated: src/State/UserVerifyProcessor.php
<?php
namespace App\State;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;
use App\Dto\Input\UserVerifyInput;
final class UserVerifyProcessor implements ProcessorInterface
{
public function process(
mixed $data,
Operation $operation,
array $uriVariables = [],
array $context = []
): mixed {
/** @var UserVerifyInput $data */
// TODO: implement verification logic
return $data;
}
}Generated: addition to src/Entity/User.php
#[Post(
uriTemplate: '/users/{id}/verify',
operationId: 'api_users_verify_post',
input: UserVerifyInput::class,
processor: UserVerifyProcessor::class,
)]Scope question
I want to be transparent about the difference with the current schema-generator scope:
- Current schema-generator: generates data model classes (entities, enums, properties) from RDF vocabularies or OpenAPI schemas
- This proposal: generates operation layer classes (State Processors, Input DTOs, custom operation attributes) from Arazzo workflows
These are two distinct layers. This could either be:
- A new
arazzoinput driver alongside the existingopenapione, scoped to operation generation - A separate package (
api-platform/arazzo-generator?) that reusesnette/php-generatorand the existing generator pipeline
Wdyt ?