manuelj555/ajax-bundle
manuelj555/ajax-bundle is a Laravel/PHP package that simplifies AJAX request handling and JSON responses, helping developers add asynchronous frontend interactions with less boilerplate, cleaner controllers, and smoother communication between JavaScript and backend code.
Reality check before anything else. This is a Symfony bundle, not a Laravel package. You cannot composer require it into a Laravel app and get working AJAX handling — Laravel has no Bundle contract, no AppKernel, and no Symfony HttpKernel event loop by default. So "getting started" for a Laravel dev means one of two things: (a) you're actually working in a Symfony codebase, or (b) you're mining the source for patterns to reimplement natively. Both are legitimate; only (a) involves installing it.
If you're genuinely on Symfony:
vendor/manuelj555/ajax-bundle/ before trusting the README. Look for AjaxBundle.php, DependencyInjection/Configuration.php (its absence means no YAML tuning), and Resources/config/services.* to see what actually gets registered.config/bundles.php (Flex) or AppKernel.php (legacy). Confirm the exact FQCN from composer.json's autoload.psr-4 — the namespace likely does not match the vendor name verbatim.curl -H 'X-Requested-With: XMLHttpRequest' and once without. The difference between those two responses is the entire value proposition — verify it before building on top.If you're on Laravel (the common case): treat this as a reference implementation, not a dependency. The first use case is a "uniform JSON envelope for XHR endpoints." You already have all the tools:
// app/Http/Controllers/Api/WidgetController.php
public function store(StoreWidgetRequest $request)
{
$widget = Widget::create($request->validated());
return response()->json([
'ok' => true,
'data' => WidgetResource::make($widget),
'message' => 'Widget created.',
], 201);
}
Then standardize the shape with a JsonResource or a small ApiResponse helper — that's the ~30-line reimplementation of what this bundle offers. Start there and only look at the Symfony source if you need inspiration for headers, status conventions, or CSRF handling on async calls.
On Symfony — the patterns this bundle is built for. The typical shape is a base controller or injected responder service that returns structured JSON and short-circuits non-AJAX requests. If the bundle exposes a responder service, prefer injecting it over extending a base controller — base classes hard-tie you to the bundle's Symfony version and break on upgrades. Something like:
public function saveAction(Request $request, AjaxResponder $responder)
{
// ... validate, persist ...
return $responder->success(['id' => $entity->getId()]);
}
Check services.xml for the real service ID; don't guess from class names. If request-detection is done via a kernel event listener, you'll see the tag in that file — that's where to hook custom behavior if needed.
On Laravel — the equivalent patterns you should actually use.
$request->ajax() (checks X-Requested-With) or $request->expectsJson() (checks Accept). Use expectsJson() for API endpoints, ajax() only for legacy XHR-only routes.BaseApiController or an ApiResponse trait/macro. Do not create per-resource response classes; the whole point is one shape.app/Http/Middleware/ForceJsonResponse.php that sets Accept: application/json on API routes — this is the Laravel-native substitute for auto-rejecting non-AJAX requests and is far more idiomatic than checking X-Requested-With.StoreWidgetRequest handles the "validate, return structured errors" flow that Symfony bundles often bundle into controllers. You get 422 JSON errors for free with expectsJson().WidgetResource::collection() / ::make() replaces hand-rolled serialization and matches the "structured JSON" promise of the Symfony bundle with better ergonomics.Integration tip — the response macro. If you want a one-liner like $responder->success(...) from the Symfony bundle, register it once:
// app/Providers/ResponseServiceProvider.php
Response::macro('api', fn ($data, int $status = 200, array $meta = []) => response()->json([
'ok' => $status < 400,
'data' => $data,
'meta' => $meta,
], $status));
Then return response()->api(WidgetResource::make($widget), 201); across every controller. That's a five-minute port of the bundle's core idea with zero dependency risk.
Frontend convention. Whether you pick up the Symfony bundle or roll your own, keep the contract stable: one envelope shape, documented status codes, and Content-Type: application/json on every response. Axios/fetch clients should never special-case individual endpoints.
You're almost certainly not going to install this in Laravel. Any composer require on a Laravel app will either fail on Symfony component constraints or install a pile of Symfony components you'll never use. Don't bridge — the "Ajax" concept is not worth a HttpKernel shim. Treat the package as source-code reading material.
Version reality. Last release 2019-05-20 means it predates PHP 8, Symfony 5/6/7, and PSR-12. Expect deprecated Symfony\Component\HttpFoundation calls, older DI YAML/XML schemas, and possible TypeError/deprecation storms on modern PHP. If you do install it on Symfony, pin the Symfony major and run composer why-not before declaring victory — transitive Symfony constraints are the real risk, not the bundle itself.
Zero dependents means zero free QA. No downstream projects means no one is smoke-testing this against new Symfony releases. Any breakage is discovered by you, in production, for the first time. Budget for that if you fork.
Watch the "opportunity" score trap. The 4.16 opportunity vs 0.005 quality divergence is a signal about the problem space (clean AJAX/JSON conventions are genuinely wanted), not about this code. Do not let the opportunity score pull the artifact into composer.json.
Extension points are limited by design. If there's no Configuration.php in DependencyInjection/, there's nothing to tune in YAML — all behavior is code-level. That's fine for a small helper but painful if you need to override headers or the response envelope: you'll fork.
Debugging tips if you do run it on Symfony:
bin/console debug:container --tag=kernel.event_listener to confirm the bundle's listeners are actually registered.bin/console debug:router isn't relevant here unless the bundle ships routes — most don't.X-Requested-With at the proxy/CDN layer before the framework — some proxies strip non-standard headers.CSRF and async endpoints. If the bundle touches CSRF at all, be very careful mixing it with Laravel's VerifyCsrfToken model. Don't try to transplant Symfony's CSRF handling into a Laravel app; Laravel's is already battle-tested and wired into Blade/Sanctum. Another reason to reimplement rather than bridge.
When to actually open the source anyway: if your team is debating "should we build an internal AJAX response standard?" this bundle is a useful 30-minute read — it shows the minimum viable surface area (detection + envelope + maybe a base controller). Use it as a checklist for what not to include, not as a spec to copy.
The honest tip: the correct Laravel day-to-day usage of manuelj555/ajax-bundle is zero lines in composer.json and occasional grep in a vendored copy for inspiration. Everything it advertises — AJAX detection, JSON responses, reduced boilerplate — is already first-party in Laravel via expectsJson(), response()->json(), Form Requests, and API Resources. Spending a day porting it is a net loss versus spending an hour standardizing on framework primitives your team already knows.
How can I help you explore Laravel packages today?