Search by

snorky22 / symfony-api-forge

snorky22

Generate Symfony services for REST APIs and webhooks from the API's documentation: curl and JSON examples become editable descriptors, from which typed HTTP clients and signed webhook consumers are regenerated.

Package info

github.com/snorky22/symfony-api-forge

Documentation

Type:symfony-bundle

pkg:composer/snorky22/symfony-api-forge

Statistics

Installs: 3

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.1.0 2026-10-30 08:36 UTC

This package is auto-updated.

Last update: 2026-10-30 08:39:23 UTC


README

Symfony bundle that generates services for REST APIs and their webhooks from their documentation: the curl examples and the JSON examples found in the API owner's docs.

curl + JSON ────api-forge:import──────────┐
object JSON ────api-forge:import-object───┤
events table,  ─api-forge:import-webhook──┼──> config/api/<api>/*.yaml ──api-forge:generate──> src/Api/<Namespace>/Generated/
payload JSON                              │    descriptors, edited by hand                     config/packages/api_<api>.yaml
  • Lenient import, strict generation: documentation examples become editable YAML descriptors, with every guess listed for review; the code is regenerated from the descriptors, so manual fixes survive.
  • Typed REST clients: one service per resource on a scoped HttpClient, JSON:API request bodies and pagination, PHPStan / PhpStorm array shapes for every response.
  • Signed webhooks: request parser checking the HMAC signature (Symfony Webhook), typed consumer methods per event (RemoteEvent), asynchronous processing with Messenger.

Requirements

  • PHP 8.2 or later
  • Symfony 7.4

Installation

composer require snorky22/symfony-api-forge

With Symfony Flex, the bundle is registered automatically. Otherwise, add it to config/bundles.php:

return [
    // ...
    Snorky22\ApiForge\ApiForgeBundle::class => ['all' => true],
];

The bundle provides the api-forge:* commands. The generated code only depends on the runtime classes of the package (Snorky22\ApiForge\Core), so the bundle can be enabled in the dev environment only (['dev' => true]).

To receive webhooks, the /webhook/{type} route of the Symfony Webhook component must be imported; the Flex recipe of symfony/webhook adds it (config/routes/webhook.yaml). For asynchronous processing, install symfony/messenger, see Webhooks.

Configuration

All the options are optional; these are the defaults:

# config/packages/api_forge.yaml
api_forge:
    descriptor_dir: '%kernel.project_dir%/config/api'   # descriptors
    namespace: 'App\Api'                                # namespace of the generated code
    source_dir: 'src/Api'                               # its directory, relative to the project
    config_dir: 'config/packages'                       # generated configuration, relative to the project

Quick start

# 1. Import documented requests (and example responses), objects and webhooks into descriptors
bin/console api-forge:import lemonsqueezy docs-examples/curl-list-customers
bin/console api-forge:import-object lemonsqueezy customers docs-examples/customer-object.json
bin/console api-forge:import-webhook lemonsqueezy --events=docs-examples/events.md \
    --payload=docs-examples/order-created-payload.json

# 2. Review config/api/lemonsqueezy/*.yaml, fix the guesses listed under "review"

# 3. Generate the services
bin/console api-forge:generate lemonsqueezy

Secrets go in .env.local, under the names given in the descriptors (e.g. LEMONSQUEEZY_API_KEY, LEMONSQUEEZY_WEBHOOK_SECRET).

public function __construct(private LemonSqueezyApi $lemonSqueezy) {}

foreach ($this->lemonSqueezy->customers->iterate() as $customer) {
    $customer['attributes']['email'];
}

#[AsRemoteEventConsumer('lemonsqueezy')]
final class LemonSqueezyWebhookConsumer extends AbstractLemonSqueezyWebhookConsumer
{
    protected function onOrderCreated(array $payload, RemoteEvent $event): void { /* ... */ }
}

examples/lemonsqueezy/ shows the result for Lemon Squeezy: descriptors, generated code and configuration, and a webhook consumer.

Documentation

Page Content
Architecture Pipeline, design choices, package layout
Workflow Adding an API or an endpoint, step by step
Descriptors Reference of the descriptor format (config/api/)
Commands Console commands and their options
Generated services Using the generated code, the runtime layer, errors, pagination
Webhooks Receiving webhooks: setup, consumers, payload types, testing
Roadmap Known limitations and next steps

Development

git clone git@github.com:snorky22/symfony-api-forge.git
cd symfony-api-forge
composer install
vendor/bin/phpunit

The tests run a small application (tests/App/TestKernel.php) with the bundle and the Lemon Squeezy example. After changing the generator, regenerate the example, which a test checks:

php tests/console api-forge:generate lemonsqueezy --dir=examples/lemonsqueezy/config/api --output=examples/lemonsqueezy

License

MIT, see LICENSE.