Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

withId executed before middlewares #310

Open
beliven-fabrizio-gortani opened this issue Mar 29, 2025 · 1 comment
Open

withId executed before middlewares #310

beliven-fabrizio-gortani opened this issue Mar 29, 2025 · 1 comment

Comments

@beliven-fabrizio-gortani
Copy link

beliven-fabrizio-gortani commented Mar 29, 2025

Hi, I'm facing a problem of execution order caused (I suppose) by the withId method of custom actions.

It seems that when I use the withId method, the system tries to resolve the value of the ID even before executing the middleware.

Below I've attach a small code for describe the problem better. The Laravel in use is 11 and the latest version of laravel-json-api.

The middleware:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Symfony\Component\HttpFoundation\Response;

class AttachGuestId
{
    public function handle(Request $request, Closure $next): Response
    {
        dd("hello world"); // <- should exit here on request
        $guestId = $request->header('guest-session-id');
        session()->set('guest_id',  $guestId); // try to set a session variable
    }
}

The API declaration:

// ...
JsonApiRoute::server('v1')
    ->prefix('v1')
    ->middleware('verified_or_guest', 'attach_guest_id') // <----The alias of the middleware here
    ->resources(function (ResourceRegistrar $server) {
             $server->resource('carts', CartController::class)
                     ->actions(function (ActionRegistrar $actions) {
                               $actions->withId()->post('confirm');
            })->middleware('attach_session_id'); //  <---- also I've try to place here
});

The method inside the controller:

// ...
public function confirm(Request $request, $cart): Responsable
    {
        GateFacade::authorize('confirm', $cart);

        // Some stuff here...
        $service = new CartService;
        $order = $service->confirm($cart);

        return new DataResponse($order);
    }

The Cart model with a Global scope set

<?php

// ...

class Cart extends Model
{
     protected function booted() {
          static::addGlobalScope(function ($builder) {
              $builder->where('guest_id',  session()->get('guest_id');
        });
     }
}

Now, when you try to execute GET /cart/:id/confirm the response is a 404, because it seems the global scope return no results and works before executing the middleware.

Image

Removing the global scope declaration inside the Cart model the response is:

Image

In this case the model was found and then the middleware was executed.

Is there any way to make sure the middleware is executing first? Thanks

@lindyhopchris
Copy link
Contributor

My best guess is this is due to Laravel's binding substitution. This is described in our docs here: https://laraveljsonapi.io/5.x/routing/#route-model-binding

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants