nuwave/lighthouse
Lighthouse is a Laravel-first GraphQL server framework. Define schemas, resolve data with Eloquent, and handle common GraphQL tasks with built-in directives and extensibility. Docs at lighthouse-php.com. Note: repo planned to move to spawnia/lighthouse.
Installation:
composer require nuwave/lighthouse
php artisan lighthouse:install
This publishes the config file (config/lighthouse.php) and sets up the GraphQL route.
Define a Schema:
Create a GraphQL schema file (e.g., graphql/schema.graphql) with your types, queries, and mutations. Example:
type User @model {
id: ID!
name: String
}
type Query {
users: [User!]! @paginate
}
First Query: Use the built-in Playground or tools like Apollo Studio to test:
query {
users {
id
name
}
}
@model to auto-generate resolvers for Eloquent models.@paginate to queries for automatic pagination support.@create, @update, and @delete directives for CRUD operations.Modular Schema Files:
Split schema into logical files (e.g., users.graphql, posts.graphql) and import them in schema.graphql:
schema {
query: Query
}
import "graphql/users.graphql"
import "graphql/posts.graphql"
Directives for Common Tasks:
@auth to protect fields/mutations.@can with Laravel policies.@validate for input validation (e.g., @validate(rule: "required|min:3")).@hasMany, @belongsTo, etc., for Eloquent relations.Custom Resolvers: For complex logic, create a resolver class and reference it in the schema:
type Query {
customData: String @resolve(class: "App\\GraphQL\\Resolvers\\CustomDataResolver")
}
Development Workflow:
php artisan lighthouse:print-schema to generate a schema file for IDE autocompletion.php artisan lighthouse:ide-helper to generate PHP type hints.Testing:
Nuwave\Lighthouse\Testing\MocksGraphQL for testing GraphQL endpoints:
public function test_users_query()
{
$response = $this->graphQL(['query' => '{ users { id name } }']);
$response->assertSuccess();
}
Performance Optimization:
config/lighthouse.php to cache parsed queries.@lazyLoad for nested relations to defer loading until needed.Laravel Features:
event(new ModelCreated($model)).type Mutation {
sendNotification(email: String!): Boolean @create(class: "App\\GraphQL\\Mutations\\SendNotification")
}
Subscriptions:
@subscribe for real-time updates:
type Subscription {
newUser: User @subscribe(class: "App\\GraphQL\\Subscriptions\\NewUser")
}
Error Handling:
config/lighthouse.php under error_handler.@throws to document expected errors in the schema.Schema Cache:
php artisan lighthouse:clear-schema-cache
php artisan lighthouse:clear-schema-cache --env=production sparingly.N+1 Queries:
@paginate or @eagerLoad for relations to avoid N+1 issues.type User {
posts: [Post!]! @hasMany @paginate
}
Input Validation:
@validate directives are placed on input types, not fields directly:
input CreateUserInput {
name: String! @validate(rule: "required|min:3")
}
Mutations and Relations:
@create on a HasOne relation), ensure the parent model exists or use @upsert:
type User {
profile: Profile @hasOne
}
type Mutation {
createProfile(userId: ID!, data: CreateProfileInput!): Profile @create(class: "App\\GraphQL\\Mutations\\CreateProfile")
}
Directives Conflicts:
@auth, @paginate) have priority. Avoid naming custom directives similarly.Query Complexity:
config/lighthouse.php to detect expensive queries:
'query_complexity' => [
'enabled' => true,
'limit' => 1000,
],
Logging:
config/lighthouse.php:
'debug' => env('APP_DEBUG', false),
Schema Validation:
php artisan lighthouse:validate to check for schema errors before deployment.Custom Directives:
use Nuwave\Lighthouse\Support\Contracts\Directive;
class CustomDirective implements Directive
{
public function __invoke($rootValue, array $args, $context, array $variables)
{
// Custom logic
}
}
config/lighthouse.php:
'directives' => [
'custom' => \App\GraphQL\Directives\CustomDirective::class,
],
GraphQL Middleware:
use Nuwave\Lighthouse\Transport\Http\Middleware\GraphQLMiddleware;
$router->middleware(GraphQLMiddleware::class)->group(function () {
// Your routes
});
Federation:
'federation' => [
'enabled' => true,
'key' => env('LIGHTHOUSE_FEDERATION_KEY'),
],
Performance:
'cache' => [
'schema' => 'file',
],
Security:
'introspection' => env('APP_DEBUG', false),
@auth and @can to restrict access:
type Mutation {
deleteUser(id: ID!): Boolean @auth @can(class: "App\\Policies\\UserPolicy", method: "delete")
}
How can I help you explore Laravel packages today?