snorky22 / symfony-api-forge
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
Type:symfony-bundle
pkg:composer/snorky22/symfony-api-forge
Requires
- php: >=8.2
- phpstan/phpdoc-parser: ^2.0
- symfony/config: ^7.4
- symfony/console: ^7.4
- symfony/dependency-injection: ^7.4
- symfony/filesystem: ^7.4
- symfony/finder: ^7.4
- symfony/framework-bundle: ^7.4
- symfony/http-client: ^7.4
- symfony/http-foundation: ^7.4
- symfony/http-kernel: ^7.4
- symfony/remote-event: ^7.4
- symfony/string: ^7.4
- symfony/var-exporter: ^7.4
- symfony/webhook: ^7.4
- symfony/yaml: ^7.4
Requires (Dev)
- phpunit/phpunit: ^11.5 || ^12.0 || ^13.0
- symfony/browser-kit: ^7.4
- symfony/messenger: ^7.4
Suggests
- symfony/messenger: To process webhook events asynchronously
Provides
None
Conflicts
None
Replaces
None
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.