Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Ajax Bundle Laravel Package

axiolab/ajax-bundle

Axiolab AjaxBundle is a lightweight Symfony bundle for handling AJAX requests, returning JSON responses, and simplifying asynchronous frontend-backend communication with reusable controllers and helpers.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony bundle, not a Laravel package. Before you write a single line of feature code, do the fit check — that's the first thing a Laravel dev should look at.

  1. Probe compatibility cheaply. Run composer require axiolab/ajax-bundle --dry-run (or against a throwaway branch). If Composer pulls symfony/http-foundation, symfony/http-kernel, or symfony/event-dispatcher, the dependency graph is telling you what you already suspect: it assumes a Symfony kernel lifecycle Laravel doesn't have. If it hard-conflicts, stop here.
  2. Read the source before trusting it. With zero stars and zero dependents there is no docs to rely on. ls vendor/axiolab/ajax-bundle/src and read every file — it'll be under twenty minutes. You're looking for exactly two behaviors:
    • An AJAX-detection helper (almost certainly a wrapper over Request::isXmlHttpRequest()).
    • A JSON response factory producing a consistent envelope like {"success": bool, "message": string, "data": ...}.
  3. Accept it won't boot in Laravel. There's no config/bundles.php, no Symfony container, and the bundle class won't auto-register — it isn't a Laravel package. Don't fight the container; treat the source as a spec for the behavior you want.
  4. First use case — dual-mode form submission. This is the one pattern the bundle genuinely exists to support: a controller action that renders a form, and on POST either redirects (normal submit) or returns JSON ({success, html, errors}) for an XHR submit. Prove that pattern out first, natively:
public function update(UpdateArticleRequest $request, Article $article)
{
    $article->update($request->validated());

    if ($request->expectsJson()) {
        return response()->json([
            'success' => true,
            'message' => 'Saved.',
            'data'    => ['id' => $article->id, 'redirect' => route('articles.index')],
        ]);
    }

    return redirect()->route('articles.index')->with('status', 'Saved.');
}

The bundle's whole value proposition fits in that snippet. That's your bar: if the package doesn't save you more than this, you don't need it.

Implementation Patterns

Mirror the two bundle behaviors natively; don't vendor the bundle.

1. AJAX detection — pick the right predicate. The bundle's detection maps to $request->ajax(), which checks the X-Requested-With: XMLHttpRequest header. That header is not sent by fetch() by default (jQuery, axios, and htmx set it; plain fetch does not). Prefer $request->expectsJson() for API-shaped responses — it keys off Accept: application/json — and use $request->ajax() only when you specifically control the client. Set the header explicitly when the client is a fetch call:

fetch(url, {
  method: 'POST',
  headers: {
    'X-Requested-With': 'XMLHttpRequest',
    'Accept': 'application/json',
    'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
  },
  body: new FormData(form),
});

2. Consistent JSON envelope — implement once, use everywhere. The bundle's structured responses are essentially a fixed shape. In Laravel, put that in a response macro or a tiny ApiResponse helper rather than retyping arrays per controller:

// AppServiceProvider::boot()
Response::macro('ajax', function (bool $ok, $data = null, string $message = '', int $status = 200) {
    return response()->json([
        'success' => $ok,
        'message' => $message,
        'data'    => $data,
    ], $status);
});

Then return response()->ajax(true, ['id' => $article->id]); — the same ergonomics the bundle promises, but owned by you and framework-idiomatic.

3. Partial rendering instead of hand-built JSON HTML. When the client needs markup, don't interpolate HTML into a JSON string. Render the Blade partial to a string and hand the bundle's-equivalent helper the markup:

if ($request->expectsJson()) {
    return response()->ajax(true, [
        'html' => view('articles._row', ['article' => $article])->render(),
    ]);
}

4. Validation errors — let Laravel do the envelope. A FormRequest automatically returns a 422 JSON payload ({"message": ..., "errors": {...}}) when the request expects JSON. If you want your own envelope, override failedValidation() on the FormRequest — that's the extension point the bundle would have provided, and it's more robust than a bundle that may never have seen Laravel's exception pipeline.

5. Centralized AJAX error handling. In Laravel 11+, register a renderable in bootstrap/app.php:

->withExceptions(function (Exceptions $exceptions) {
    $exceptions->render(function (Throwable $e, Request $request) {
        if ($request->expectsJson() && ! $request->isMethod('GET')) {
            return response()->ajax(false, null, $e->getMessage(), 500);
        }
    });
})

That is the "centralized error handling for AJAX failures" bullet from the bundle description, done with first-party tooling.

6. Keep the non-AJAX path fully working. Progressive enhancement is the whole point of the dual-mode controller: if the JS bundle fails, the form still submits and redirects. This also means you can test the feature with PHPUnit/livewire-style HTTP tests without a browser, which you can't do if you've committed to a bundle you can't boot.

Gotchas and Tips

  • The namespace is a smell. Published under mathieumuller but namespaced Axiolab\... with zero stars and zero dependents — treat provenance as unverified and don't pull it into anything that ships.
  • Framework mismatch is the headline gotcha. Symfony bundles need the Symfony DI container, event dispatcher, and HTTP kernel. Laravel's service container, middleware pipeline, and request lifecycle are different. Any attempt to bridge it duplicates what Laravel already ships ($request->ajax(), $request->expectsJson(), response()->json(), FormRequest, CSRF middleware).
  • fetch() doesn't set X-Requested-With. This is the #1 reason "AJAX detection" appears to fail. The bundle's detector — like Laravel's ajax() — will return false for a bare fetch. Use expectsJson() or set the header deliberately.
  • CSRF. A JSON POST from JS needs either the X-CSRF-TOKEN header (from your blade meta tag) or a _token field in the payload. Without it you get 419 responses that look like "AJAX broken" but are really CSRF failures. Verify your web middleware group is applied to the route.
  • Accept: application/json drives a lot of Laravel behavior. It changes validation error responses, AuthenticationException handling (401 JSON instead of a redirect), and abort() output. Send it from the client and use $request->expectsJson() in the controller so detection and error handling line up.
  • Don't put raw HTML into a JSON string by hand. Render the partial (view(...)->render()) — escaping and Blade directives get applied correctly, and you avoid the quoting bugs the bundle was presumably created to solve.
  • Extension points you actually want: Response::macro for the envelope, FormRequest::failedValidation() for error shape, exception renderables for global AJAX error handling, and a response middleware if you need to normalize Content-Type. All first-party, all upgradable.
  • Debugging tip: log $request->header('X-Requested-With'), $request->header('Accept'), and $request->expectsJson() together when a "detection" branch misbehaves. The bug is almost always client-side header config, not server logic.
  • Adoption verdict. Don't add this as a dependency in a Laravel app. Read it, mirror the two behaviors natively, and log the rejection so nobody re-litigates it next quarter. For a mixed Symfony/Laravel shop, scope it to the Symfony services only — and even there, Symfony's UX/Turbo/Stimulus components are the maintained path.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle