ruwork/api-bundle
Ruwork API Bundle is a Symfony bundle for building JSON APIs in PHP. It reduces boilerplate around request handling, validation, serialization, and error responses, helping developers create consistent, maintainable backend APIs that integrate smoothly with Symfony applications.
This is a legacy Symfony bundle (last tagged release August 2018, archived upstream), so treat it as maintenance-only. Before writing a line of application code:
composer.json will constrain Symfony to the 3.x/early-4.x range. If you are on Symfony 5+, you will almost certainly need --ignore-platform-reqs or a fork; do not fight this in production — pin the major.config/bundles.php (or AppKernel::registerBundles() on 3.x):
Ruwork\ApiBundle\RuworkApiBundle::class => ['all' => true],
src/RuworkApiBundle.php, src/DependencyInjection/, and the Resources/config/*.xml service definitions are the actual documentation. The README on the archived repo is the secondary source.First use case: stand up one controller returning an entity and hit it with curl -i. If the bundle's listeners are active you should get a JSON Content-Type, a consistent error envelope on a thrown exception, and (if configured) HTTP-appropriate status codes. If you get HTML or a stack trace, the listener priority is wrong or the bundle isn't registered — check debug:event-dispatcher kernel.exception.
NotFoundException, validation exceptions) from services and let the kernel exception listener format them. Keep controllers returning data objects only.JsonResponse. If the bundle exposes a response factory or view service, inject it rather than constructing JsonResponse by hand — that is the single seam you would otherwise have to rewrite if you migrate off the bundle. Wrapping it in your own ApiResponder service now makes the eventual replacement a one-file change.serializer.normalizer tag rather than reconfiguring the serializer from scratch. Two competing serializer configs is the classic failure mode.ConstraintViolationListInterface to a structured 422 body in one subscriber or exception listener. If the bundle doesn't do this, add a single kernel.exception listener after the bundle's (lower priority number), so the bundle handles the generic case and yours handles validation specifically.Accept: application/json in tests and clients. Many 2018-era bundles key their listeners on the request format; a missing Accept header silently disables the JSON error handling and you get the framework's HTML error page instead.assertJsonStructure / assertJsonPath) so a future Symfony upgrade that breaks the listener is caught immediately. This is the cheapest insurance for an archived dependency.ErrorHandler/ProblemNormalizer (4.4+) or API Platform instead. The only justified use is inheriting an existing codebase.composer.json require before upgrading Symfony. A transitive Symfony minor bump is the most likely thing to break this bundle, and there will be no upstream fix — budget for vendoring/forking.kernel.exception listener is registered and at what priority (debug:event-dispatcher). Yours must sit below it to override selectively.dev and mask them in prod. Test the error envelope under APP_ENV=prod APP_DEBUG=0 explicitly; this is where the "works on my machine" tickets come from.Accept header / request format coupling. As above — missing or */* Accept frequently bypasses JSON handling. Assert the header in functional tests.DependencyInjection/Configuration.php for the actual config tree; the README will be stale or incomplete. Use config:dump-reference ruwork_api (adjust the alias) if the extension defines one.decorates:) rather than editing vendor code — that survives a composer update and documents your divergence.getPrevious()-in-error-messages hardening. Audit what it echoes back in prod before shipping; strip exception messages for non-HttpException types yourself.How can I help you explore Laravel packages today?