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 Laravel Package

bnnvara/graphql

A Laravel/PHP GraphQL package from bnnvara that helps integrate GraphQL schemas and APIs into applications, offering a practical foundation for building and querying GraphQL services in Laravel projects.

View on GitHub
Deep Wiki
Context7

Getting Started

The package is a thin abstraction over webonyx/graphql-php — think of it as opinionated glue for schema definition, type registration, and resolver wiring in Laravel, not a full-featured GraphQL server like Lighthouse. Because it has zero stars and zero dependents, treat it as an internal/utility package with no community safety net.

Install and inspect before you trust it:

composer require bnnvara/graphql

Then immediately read the package source:

ls vendor/bnnvara/graphql/src
cat vendor/bnnvara/graphql/composer.json
cat vendor/bnnvara/graphql/README.md 2>/dev/null

The composer.json tells you the exact webonyx/graphql-php version it pins and whether it registers a service provider or publishes config. That pin is the single most important fact — the webonyx/graphql-php API drifted across major versions (v14 → v15 changed resolver signatures, type loader expectations, and GraphQL\Type\Definition\Type helpers).

Where to look first:

  1. config/graphql.php (if published) — schema path, type namespace, root query/mutation class.
  2. The package's base Type, Query, Mutation, and Field classes — these are what you extend.
  3. Its service provider — tells you what is bound in the container and how schemas are resolved.

First use case — wire up a single query end-to-end before building anything else. Define one Query subclass returning a string, register it as the root query type, and hit it through whatever controller or route the package provides. If you can get { hello } returning {"data":{"hello":"world"}}, you understand the wiring; everything else is repetition.

Implementation Patterns

Schema-as-code with a root type. Most abstractions of this shape expect you to define a root Query type class that composes field definitions. The pattern:

class QueryType extends Type
{
    public function fields(): array
    {
        return [
            'user' => [
                'type' => $this->type(UserType::class),
                'args' => ['id' => Type::nonNull(Type::id())],
                'resolve' => fn ($root, array $args) => User::find($args['id']),
            ],
        ];
    }
}

Keep resolvers thin — delegate to services or query objects. GraphQL resolvers are the worst place to hide business logic because they are invoked per-field, and N+1 problems compound silently.

Type registry via lazy callables. If the package exposes a type() helper that resolves class names lazily, use it religiously. Circular type references (User → Post → User) will blow up at boot if you instantiate types eagerly. If the package does not provide lazy resolution, wrap types in closures yourself:

'type' => fn () => $this->types[UserType::class]

DataLoader for N+1. webonyx/graphql-php ships a Deferred/promise-aware execution path, but you must opt in. If the package doesn't surface a DataLoader, build one on top of the executor:

$loader = new DataLoader(fn (array $ids) => User::whereIn('id', $ids)->get()->keyBy('id'));

Return $loader->load($id) from resolvers on nested fields. Batch by request, never singleton — the loader must be scoped to a single GraphQL execution.

Middleware for auth and error shaping. GraphQL collapses many HTTP concerns into one endpoint. Do auth per-field, not per-route:

'resolve' => fn ($root, $args, $ctx) => $ctx['user']->can('view', $user)
    ? $user
    : throw new AuthorizationException(),

Return structured errors via GraphQL\Error\UserError so clients get extensions rather than raw exceptions. A global formatError callback (check whether the package exposes one) is the cleanest place to strip stack traces in production.

Integration with Laravel validation. Resolve arguments to a DTO, then run a standard Validator::make($args, $rules). Do not throw ValidationException directly — GraphQL expects either a UserError or a field-level error. Wrap and rethrow with a field path.

Gotchas and Tips

Unknown maintenance status. Zero stars and zero dependents on Bitbucket means no third-party bug reports, no CVE tracking, and no guarantee it works with the current webonyx/graphql-php. Pin the webonyx/graphql-php version in your own composer.json and run the full test suite after any composer update. If you need long-term support, budget for the possibility of forking this package or replacing it with a few hundred lines of custom bootstrapping.

Bitbucket dependency is a real risk. If the repo goes private or is deleted, composer install breaks for every new teammate and every CI run. Mirror it: fork into your own VCS, tag it, and depend on the fork. Even better, vendor the relevant classes into app/GraphQL if the abstraction is small — you will likely end up modifying it anyway.

Resolver signatures are version-sensitive. webonyx/graphql-php changed resolver invocation between versions (argument count, ResolveInfo shape). If you see Too few arguments to function or resolver $info being undefined, check the pinned version in composer.lock against the resolver docs for that release, not the latest docs.

Eager type instantiation loops. Circular references are the number-one startup crash. If the container resolves all types at boot, you will get infinite recursion. Always verify by booting the schema in a test:

public function test_schema_builds(): void
{
    GraphQL::schema()->assertValid();
}

Run that test in CI before every deploy — schema build failures are the GraphQL equivalent of a broken migration.

Error leaking. By default webonyx/graphql-php returns "Internal server error" for uncaught exceptions but includes debug info when debug is on. Confirm the package respects config('app.debug'). In production, set debug => false explicitly and add a formatError that logs the original exception while returning a safe message.

N+1 hides in relationships. A naive PostType resolver calling $post->author per post is the classic trap. Instrument with Laravel Debugbar or a query-count assertion in feature tests. If the package gives you no loader hook, use @defer (if supported) or restructure into batched root queries.

Complexity limits. Public GraphQL endpoints are trivially DoS-able with deeply nested queries. webonyx/graphql-php supports QueryComplexity and DepthLimit validation rules — verify the package wires them. If not, add them yourself in the execution middleware; a missing depth limit is a production incident waiting to happen.

Extension points worth checking. Before extending anything, grep for protected function and protected $ in the base classes — most thin abstractions expose one or two override hooks (type resolution, resolver wrapping, error formatting) that save you from copy-pasting framework code. Document those hooks in your own README so the next developer on the team doesn't rediscover them.

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.
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log
hsluv/hsluv
seampact/codegen