deinternetjongens/lighthouse-utils
A utility package for Laravel Lighthouse GraphQL that provides reusable directives and helpers for common schema tasks. It helps streamline GraphQL API development in Laravel by reducing boilerplate and making custom fields, queries, and schema logic easier to build and maintain.
Install alongside Lighthouse in a Laravel app:
composer require deinternetjongens/lighthouse-utils
The package targets the Lighthouse 2.x/3.x era (last release Sept 2018), so pin nuwave/lighthouse to a compatible version first. Composer will usually tell you immediately if the constraint clashes.
Register the service provider if auto-discovery doesn’t pick it up (older Laravel), and check whether the package ships a config file to publish:
php artisan vendor:publish --provider="DeInternetJongens\LighthouseUtils\LighthouseUtilsServiceProvider"
Look here first: vendor/deinternetjongens/lighthouse-utils/src/ — the directive class is the whole package. Read its name() and args()/directiveFields() methods to confirm the exact directive handle and supported arguments. The README on the (now unknown) repo is the secondary source; trust the source code over stale docs.
Confirm Lighthouse itself is wired up: a schema in routes/graphql/schema.graphql (or graphql/schema.graphql depending on version), config/lighthouse.php pointing at it, and the GraphQL endpoint reachable in GraphQL Playground at /graphql.
First use case: take one simple Eloquent-backed type and let the directive generate the write mutations for it.
type Post {
id: ID!
title: String!
body: String
}
type Mutation {
# the package expands this into create/update/delete
post: Post @crud(model: "App\\Models\\Post")
}
Run php artisan lighthouse:validate-schema, open Playground, introspect the Mutation type, and you should see createPost, updatePost, deletePost plus generated input types. Wire up one create call end-to-end before expanding to more types — that validates model resolution, fillable config, and auth in one pass.
Schema-first, one directive per type. The package’s value is turning a type definition into a CRUD surface, so keep schema files split by domain and #import them into the root schema. Put the generated block in its own mutations/post.graphql so you can later replace it with hand-written fields without touching the type.
Reads stay native Lighthouse. Use @all, @paginate, @find, @field for queries; let this package own only the mutations. That keeps the blast radius small when you eventually migrate off it.
Convention over configuration. Model resolution typically keys off the type name or an explicit model: argument. Lean on conventions (type Post → App\Post/App\Models\Post) so a new resource is one type block plus one directive. Where the directive supports narrowing (only:, except:, per-operation arguments), use it instead of deleting generated fields by hand — deleting is fragile if the directive runs again.
Pair with policies for authorization. Generated mutations don’t know your business rules. Add @can / @guard on the mutation fields or enforce it in Laravel policies on the model. Test a forbidden update explicitly; it’s the most common silent hole in auto-generated CRUD.
Validation via the model layer. These generators generally derive validation from Laravel’s validation rules or rely on $fillable/$guarded. Keep rules on FormRequests or a rules() convention the directive understands, and add explicit @rules / validation directives on top for anything non-trivial (uniqueness, nested arrays, enums).
Customize by overriding, not editing vendor code. If a generated field is 90% right, define the field manually with the same name and standard Lighthouse directives (@create, @update, @delete). Manual definitions typically take precedence or let you disable the generated one via the directive’s except: argument. This is also your migration path.
Testing pattern. Assert the schema shape once (snapshot/introspection test that createPost exists with the expected input), then write behavior tests through $this->graphql(...) for happy path, validation failure, and unauthorized access per generated mutation. The generation itself rarely breaks; the model assumptions do.
Local workflow.
php artisan lighthouse:validate-schema # catch malformed SDL after edits
php artisan lighthouse:clear-cache # if schema caching is on
Keep Playground open; introspection is faster than reading the generator to see what it actually produced.
@create / @update / @delete / @upsert directives and the lighthouse:query/lighthouse:mutation generators. On any modern Lighthouse, this package is redundant at best and a Composer conflict at worst. Check the installed Lighthouse version before investing; if you’re on v4+, prefer native directives.src/. With the repository unavailable, README snippets may not match the installed tag. A wrong argument fails silently or throws an unhelpful schema-build error.CreatePostInput) collide with hand-written ones of the same name. Lighthouse errors on duplicate type definitions — grep your schema before adding custom inputs.$fillable (or is blocked by $guarded) will be accepted by GraphQL and silently dropped on save. Symptom: mutation returns success, column stays null. Check $fillable before debugging the directive.belongsTo/belongsToMany connect/disconnect inputs generally need manual fields. Don’t expect nested writes.@with or eager-load in the resolver/model to avoid query explosions.lighthouse:clear-cache part of your local loop, and remember to run cache-warm in deploy.config/lighthouse.php route.middleware), and that unauthenticated calls to deletePost actually 401/403.debug is off so SQL/stack traces don’t leak through mutation error extensions.config/lighthouse.php under namespaces, or a field middleware in field_middleware. Overriding a generated field is the cleanest customization; subclassing the package’s directive is the cleanest way to add behavior (audit logging, tenancy scoping) without forking.$fillable → check policy → check validation rules → only then read the directive source. The directive is rarely the bug.How can I help you explore Laravel packages today?