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

Graphql Files Bundle Laravel Package

youshido/graphql-files-bundle

A Symfony bundle that adds file upload support to the Youshido GraphQL library, mapping multipart requests to file arguments in your schema. A lightweight option for smaller projects that need upload handling without a heavier framework.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the bundle and its peer GraphQL library with Composer, then register it in your Symfony kernel/bundles config:

composer require youshido/graphql-files-bundle
// config/bundles.php (or AppKernel::registerBundles for older Symfony)
return [
    // ...
    Youshido\GraphQLFilesBundle\GraphQLFilesBundle::class => ['all' => true],
];

Where to look first: open the bundle's src/ (or lib/) and Resources/config to find (a) the GraphQL scalar/type it registers for file inputs and (b) the request listener that parses multipart uploads per the GraphQL multipart request spec. Those two pieces are the whole package — everything else is wiring.

First use case: a mutation that accepts an uploaded file and returns a URL. Expose the bundle's file scalar on an argument, and your resolver receives a Symfony\Component\HttpFoundation\File\UploadedFile:

use Youshido\GraphQL\Type\Scalar\AbstractScalarType; // plus the bundle's file type

$config->addField('uploadAvatar', [
    'type' => Type::string(),
    'args' => [
        'file' => ['type' => Type::nonNull(new FileType())],
    ],
    'resolve' => function ($value, array $args) {
        /** @var \Symfony\Component\HttpFoundation\File\UploadedFile $file */
        $file = $args['file'];
        $name = bin2hex(random_bytes(8)) . '.' . $file->guessExtension();
        $file->move($this->getParameter('uploads_dir'), $name);
        return '/uploads/' . $name;
    },
]);

Client-side, send a multipart request in the spec's operations / map / file-part shape (Apollo Upload Client or a hand-built FormData both work):

operations = {"query":"mutation($file: File!){ uploadAvatar(file:$file) }","variables":{"file":null}}
map        = {"0":["variables.file"]}
0          = <binary file>

Implementation Patterns

Treat file uploads as part of a mutation, not a query. Pair the file argument with the rest of the mutation's data so validation and persistence are one atomic resolver. Extract validation and storage into a small service (e.g. AvatarUploader) and inject it — don't stuff move() calls into type classes.

Normalize storage across backends. Have the resolver delegate to a service that returns a DTO/entity, so you can later swap local disk for S3 or Flysystem without touching the schema:

'resolve' => fn ($v, $args) => $this->container->get(Uploader::class)->store(
    $args['file'], 'avatars'
)

Validate against the UploadedFile, not the GraphQL type. Use Symfony validators or File constraints on the underlying UploadedFile; the scalar only guarantees you received an upload object. Check isValid(), size, and MIME (getMimeType() / getClientMimeType() — trust the former).

Keep the scalar in your own schema builder. If you build types programmatically, centralize the FileType instantiation in a factory so you can swap in a custom scalar later without hunting through every mutation.

Testing: drive the integration with a real HTTP call, since the multipart parsing is the risky part. A curl or HttpClient test with the three-part body above validates the whole pipeline; unit-test the storage service separately. Add a smoke test that asserts the resolver actually receives an UploadedFile and not an array/string.

Auth/authorization: the resolver still runs under your normal security context, so apply $config->addField(..., ['resolve' => ..., 'args' => ...]) with the usual access checks. Don't rely on the bundle for CSRF or auth.

Gotchas and Tips

  • This is a very small, low-traffic package (4 stars, zero dependents at time of writing). Pin the version, read its source before relying on it, and avoid assuming active maintenance. If the spec-compliant parsing breaks on your PHP/Symfony version, you may need to fork or replace it with a small listener of your own.
  • PHP upload limits are the usual cause of "it works in tests, fails in prod." Tune upload_max_filesize, post_max_size, and max_file_uploads; when post_max_size is exceeded PHP empties $_POST/$_FILES silently, so the GraphQL request looks empty rather than failing loudly.
  • Temporary files vanish at end of request. If a resolver throws after receiving the file, the tmp file is cleaned automatically — but if you persist a path to the tmp location, it will be gone. Always move()/copy during the resolver.
  • The map field is exact-match sensitive. A malformed multipart body (wrong field names, missing map, non-string keys) usually surfaces as "file argument is null" or a scalar coercion error. Enable GraphQL debug output and log the parsed variables first when debugging.
  • Proxy/body-reading middleware (WAFs, some auth bundles, Request::getContent() in a listener) can consume the request body before the bundle sees it. Keep such middleware from touching multipart POSTs.
  • Extension point: if you need a different input shape (e.g. base64-in-JSON for small images), define a custom scalar and register it instead of the bundle's — the bundle's main value is the multipart decoding, not the scalar.
  • Don't trust getClientOriginalName() in stored filenames or headers; generate your own name and derive extensions via guessExtension().
  • Symfony version skew is the most likely integration failure for a package this old; check the bundle's composer.json constraints against your framework version before committing, and be ready to override the request-listener service in services.yaml if behavior needs adjusting.
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.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core