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

Grapes Bundle Laravel Package

msales/grapes-bundle

msales/grapes-bundle integrates the Grapes GraphQL library into Symfony applications, offering service container wiring, schema and resolver configuration, and streamlined query execution for PHP APIs. It helps teams build maintainable GraphQL endpoints with familiar Symfony conventions.

View on GitHub
Deep Wiki
Context7

Getting Started

Know what you're installing first. msales/grapes-bundle is a Symfony bundle that wires the msales/grapes API-client library into a Symfony container. There is no Laravel service provider, no facade, no publishable config, and no auto-discovery. For a Laravel codebase this means the bundle itself provides almost nothing — its entire value is a handful of DI service definitions and parameter mappings you can read in a few minutes. The latest release, 1.1.0, added Symfony 4 support (previously the bundle targeted Symfony 3 only). That is a compatibility bump, not a modernization: PHP constraints are still 7.x-era, and there is still no Laravel integration.

Minimal adoption path:

  1. Check installability before anything else. The 1.1.0 release widens Symfony constraints to include Symfony 4, but the package remains pinned to PHP 7.x and Symfony 3/4. Run composer require msales/grapes-bundle --dry-run and composer why-not msales/grapes-bundle on your current stack. On PHP 8.1+ / Laravel 9+ expect a hard block. Symfony 4 support does not help here — Symfony 4 is itself EOL and incompatible with modern PHP.
  2. Read the bundle class, its DI Extension, and Resources/config/services.* — in that order. Those three files are the whole package. Whatever the bundle registers is what you will be re-registering.
  3. Read the msales/grapes README for the actual runtime behavior (client, request, response types). The bundle contributes config, not logic.
  4. First use case: port the bundle's client service into a small GrapesServiceProvider, bind the grapes client interface as a singleton, inject it into one gateway class, and make a single GET call to a known endpoint from php artisan tinker.

If you are starting fresh, stop here and use Laravel's Http client or Guzzle/Saloon instead. Only proceed if you have existing code that already speaks msales/grapes types and you need the container wiring to match.

Implementation Patterns

Port the config, don't depend on the bundle. Extract the bundle's parameters into config/services.php (or a dedicated config/grapes.php), and translate each Symfony service definition into a Laravel binding:

// app/Providers/GrapesServiceProvider.php
public function register(): void
{
    $this->app->singleton(GrapesClient::class, function ($app) {
        return new GrapesClient(
            baseUri: config('services.grapes.base_uri'),
            timeout: config('services.grapes.timeout', 5),
        );
    });
}

Keep env() calls inside config files only, exactly as you would for any other Laravel service.

Hide the dependency behind your own interface. Given 4 stars, zero dependents, and a maintenance history that consists of a single Symfony 4 compatibility bump years after the fact, do not let grapes types leak into controllers, jobs, or domain code. Define App\Contracts\InventoryClient (or similar), implement it with a GrapesInventoryClient adapter, and bind the interface. Swapping to Http:: later becomes a one-file change.

Keep HTTP work in gateway classes. One class per remote service, constructor-injected client, methods that return your own DTOs (or arrays), and exceptions normalized to Laravel-friendly ones. Controllers and jobs call the gateway; nothing else knows grapes exists.

Queue workers: build per job, fail loudly. Old client libraries frequently lack retry/backoff. Set explicit timeouts in the binding, catch transport exceptions in the gateway, and let the job's $tries / $backoff handle retries rather than relying on the library. Do not reuse a client across long-lived worker iterations if it caches state.

Testing pattern. Because you hid the client behind an interface, most tests bind a fake and never touch grapes:

$this->app->instance(InventoryClient::class, new FakeInventoryClient());

For the adapter's own test, inject a Guzzle/PSR-18 mock handler into the underlying grapes client, or (simpler) wrap any PSR-18 call in Laravel's Http client so Http::fake() works with zero extra setup.

Integration tip — adapter, not migration. If only one or two endpoints still use grapes, add a GrapesAdapter next to your newer Http-based clients. Both satisfy the same interface, so you can migrate endpoint by endpoint and delete the provider when the last caller is gone.

Gotchas and Tips

  • It is not a Laravel package. No extra.laravel.providers, no config/ to publish, no Artisan commands. Any guide that says "install and configure" assumes Symfony Flex and will not apply.
  • Symfony 4 support arrived only in 1.1.0, and it changes nothing for Laravel. The 1.1.0 release lifts the ceiling from Symfony 3 to Symfony 4, but Laravel ships its own symfony/* constraints and modern Laravel lives on Symfony 6/7. A minor release that adds support for an already-EOL Symfony major is not a step toward Laravel compatibility. --ignore-platform-reqs may technically install it and leave you with a container that breaks at runtime. Treat an install failure as a signal, not an obstacle.
  • Abandonment risk is the headline. Four stars, zero dependents, and a single minor release (1.1.0) that merely adds Symfony 4 support. There is no evidence of ongoing maintenance, security response, or Laravel awareness. If you adopt it, pin the exact version in composer.json, commit the lock file, and consider vendoring the two or three classes you actually use into app/Support instead of carrying the dependency.
  • Debugging order: (1) does the binding resolve? app(GrapesClient::class) in tinker; (2) is the base URI/timeout actually populated? dump the config; (3) is the failure a transport error or a DI error? Nine times out of ten it is wiring, not the library, because the library surface you use is tiny.
  • The DI extension is the only extension point. There is no event system, middleware pipeline, or plugin hook. Whatever parameters the extension exposes are your entire configuration surface — copy them into your provider rather than trying to extend the bundle. The 1.1.0 release did not add new extension points; it only adjusted version constraints.
  • Do not mix clients in one class. A gateway that sometimes uses grapes and sometimes uses Http is untestable and impossible to reason about during an incident. Pick one per adapter.
  • Zero dependents means zero examples. Search results, Stack Overflow answers, and blog posts effectively do not exist. Budget time to read the source; it is small enough that this is realistic, but do not expect to find an answer online. The 1.1.0 release notes are one line long — that is the level of documentation you should expect.
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.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings