silverbackis/api-components-bundle
A Symfony bundle for building clean JSON APIs with reusable components. It adds conventions and helpers for API resources, request handling, serialization, validation, pagination, and error responses, reducing boilerplate while keeping controllers thin and responses consistent.
This is an API Platform/Symfony bundle that exposes a components API (components, groups, drafts, publishing) — not a Laravel package with a service provider. Treat it as a remote HTTP service you integrate with, and only pull it into require-dev-style tooling if you truly need in-process access.
"components-web-app/api-components-bundle": "2.0.0-alpha.30" — no caret range. Alpha releases carry behavioral changes (this one adds new 422 rules), and you do not want a transitive resolve silently changing validation semantics.Component/ComponentGroup entities and their relations, ComponentVoter (authorization + the cycle guard), and tests/Functional — since 2.0.0-alpha.30 removed Behat entirely, tests/Functional is now the only executable specification of behavior.422 keyed on component. Do the same for assigning a group an owner from inside that group — you should get a 422 keyed on components.Consume over HTTP, not in-process. From Laravel, wrap the API in a small client (Http::baseUrl(...)->withToken(...)->acceptJson()->throw()), one method per operation, and map responses to your own DTOs/resources. Keep the bundle's JSON shape out of your domain layer so upstream alpha churn stays contained.
Model drafts explicitly. A published component and its draft are treated as one node for cycle purposes. Mirror that in your own code: any local tree/graph index you build should key on the logical component, not on the draft-vs-published row, or your local cycle checks will disagree with the server's.
Validate cycles client-side, but never rely on it. The server now rejects self-containing placements at any depth. Replicate the ancestor walk in your form request / DTO validation so users get feedback before a round trip, but keep the 422 handler — you cannot guarantee your local graph is current.
Two distinct error keys. Placement violations come back as 422 on component; group-owner violations come back as 422 on components. Handle both keys explicitly in your exception → validation-error translation layer instead of a generic "something went wrong".
Testing pattern. The package moved to PHPUnit functional tests on API Platform's ApiTestCase with a per-process in-memory SQLite database and a debug-kernel group. Adopt the same discipline in your integration tests: RefreshDatabase, no cross-process state assumptions, and assert on the response body/status rather than merely calling the endpoint — both PHPUnit configs in the bundle now fail on Risky, and yours should too.
CI shape. The functional suite runs on every legacy Behat CI leg and inside Infection. If you run mutation testing against your integration layer, expect the cycle-guard logic to be a high-value mutation target.
ComponentVoter used to recurse forever on a pre-existing cycle. It no longer does, but "no longer hangs" is not "your data is fine" — audit for components/groups already arranged in a self-containing position and repair them, or authorization results will be quietly wrong rather than loudly broken.features/ paths (assets, the golden scaffold) in your own tooling or docs, they moved to tests/Functional/assets and tests/Functional/Fixture/scaffolds. Any script globbing features/** now silently matches nothing.symfony/yaml and symfony/translation are now declared directly because Behat's dependency graph previously supplied them. If your integration harness leaned on the same implicit availability, declare them yourself.ComponentVoter is actively changing.How can I help you explore Laravel packages today?