Skip to content

Arazzo spec #443

@pierreboissinot

Description

@pierreboissinot

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.yaml

The command would:

  1. Parse the Arazzo file
  2. Load the current OpenAPI spec generated by API Platform
  3. Diff: detect operationIds referenced in Arazzo but absent from OpenAPI
  4. 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 == 200

Expected 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 arazzo input driver alongside the existing openapi one, scoped to operation generation
  • A separate package (api-platform/arazzo-generator?) that reuses nette/php-generator and the existing generator pipeline

Wdyt ?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions