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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions