Laravel Lighthouse EnsureXHR middleware gets in the way of file upload

52 views Asked by At

I've taken the example from the Lighthouse(v6) documentation for uploading a file.

  1. Added the mutation
type Mutation { upload(file: Upload!): String }
  1. Then create a custom Upload mutation class
final readonly class Upload
{
    /** @param  array{}  $args */
    public function __invoke(null $_, array $args)
    {
        dd($args);
    }
}

Went on to write the first test

public function upload_profile_photo_successfully(): void
    {
        $operations = [
            'query' => /** @lang GraphQL */ '
        mutation ($file: Upload!) {
            upload(file: $file)
        }
    ',
            'variables' => [
                'file' => null,
            ],
        ];

        $map = [
            '0' => ['variables.file'],
        ];

        $file = [
            '0' => UploadedFile::fake()->create('test.pdf', 500),
        ];
        $user = $this->createRandomUser()->getUser();
        $this->actingAs($user);

        $this->multipartGraphQL($operations, $map, $file)->dd();
    }

When I run the test the EnsureXHR middleware throws the exception

Content-Type multipart/form-data; is forbidden

which is expected from the middleware code

public const FORM_CONTENT_TYPES = [
   'application/x-www-form-urlencoded',
   'multipart/form-data',
   'text/plain',
];

...

if (Str::startsWith($contentType, static::FORM_CONTENT_TYPES)) {
   throw new BadRequestHttpException("Content-Type {$contentType} is forbidden");
}

How can I do the file upload with the XHR in place?

I tried deactivating the XHR middleware and it works fine, but that's not what I want to accomplish.

1

There are 1 answers

1
Alex On BEST ANSWER

When reading the middleware code I can see the following:

if ($request->header('X-Requested-With', '') === 'XMLHttpRequest') {
    return $next($request);
}

So the solution is to add the X-Requested-With: XMLHttpRequest header to your request to allow your request to pass the EnsureXHR middleware.

Alternatively, remove the EnsureXHR middleware when running your test suite since it makes no sense to force only XHR requests when testing unless you are doing browser testing.