Try Live
Add Docs
Rankings
Pricing
Docs
Install
Install
Docs
Pricing
More...
More...
Try Live
Rankings
Enterprise
Create API Key
Add Docs
Laravel GraphQL
https://github.com/rebing/graphql-laravel
Admin
This package provides an integration of GraphQL for Laravel, allowing for the creation of queries
...
Tokens:
26,996
Snippets:
104
Trust Score:
8.2
Update:
4 months ago
Context
Skills
Chat
Benchmark
79.3
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# Laravel GraphQL Laravel GraphQL is a comprehensive GraphQL integration package for Laravel applications, built on top of the webonyx/graphql-php library. It provides a structured, Laravel-idiomatic way to create GraphQL APIs with support for queries, mutations, types, schemas, validation, authorization, and advanced features like pagination, batching, and automatic persisted queries. The package bridges the gap between GraphQL's powerful query language and Laravel's elegant framework, making it easy to build performant and type-safe APIs. This library extends beyond basic GraphQL functionality by offering Laravel-specific features such as Eloquent integration via SelectFields for optimized database queries, middleware support at multiple levels (HTTP, execution, and resolver), privacy controls on fields, and built-in validation using Laravel's validation system. It supports multiple schemas with different configurations, allowing developers to create separate GraphQL endpoints for different purposes (e.g., public API vs authenticated user endpoints) while sharing common types and logic. ## Installation and Configuration Installing the package via Composer and publishing configuration ```bash # Install the package composer require rebing/graphql-laravel # Publish the configuration file php artisan vendor:publish --provider="Rebing\GraphQL\GraphQLServiceProvider" ``` ```php // config/graphql.php - Basic schema configuration return [ 'route' => [ 'prefix' => 'graphql', 'middleware' => [], ], 'default_schema' => 'default', 'schemas' => [ 'default' => [ 'query' => [ App\GraphQL\Queries\UsersQuery::class, ], 'mutation' => [ App\GraphQL\Mutations\UpdateUserPasswordMutation::class, ], 'types' => [ App\GraphQL\Types\UserType::class, ], 'middleware' => null, 'method' => ['GET', 'POST'], ], 'user' => [ 'query' => [ App\GraphQL\Queries\ProfileQuery::class, ], 'middleware' => ['auth'], 'route_attributes' => [ 'domain' => 'api.example.com', ], ], ], 'types' => [], 'security' => [ 'query_max_complexity' => null, 'query_max_depth' => null, 'disable_introspection' => false, ], ]; ``` ## Creating a GraphQL Type Defining a type that represents your data structure ```php <?php namespace App\GraphQL\Types; use App\Models\User; use GraphQL\Type\Definition\Type; use Rebing\GraphQL\Support\Facades\GraphQL; use Rebing\GraphQL\Support\Type as GraphQLType; class UserType extends GraphQLType { protected $attributes = [ 'name' => 'User', 'description' => 'A user', 'model' => User::class, ]; public function fields(): array { return [ 'id' => [ 'type' => Type::nonNull(Type::int()), 'description' => 'The id of the user', ], 'email' => [ 'type' => Type::string(), 'description' => 'The email of user', 'resolve' => function($root, array $args) { return strtolower($root->email); } ], 'name' => [ 'type' => Type::string(), 'description' => 'The name of user', ], 'created_at' => [ 'type' => Type::string(), 'description' => 'Creation timestamp', ], 'profile' => [ 'type' => GraphQL::type('Profile'), 'description' => 'User profile relation', ], ]; } } ``` ## Creating a Query Building a query to fetch data from your application ```php <?php namespace App\GraphQL\Queries; use Closure; use App\Models\User; use GraphQL\Type\Definition\ResolveInfo; use GraphQL\Type\Definition\Type; use Rebing\GraphQL\Support\Facades\GraphQL; use Rebing\GraphQL\Support\Query; class UsersQuery extends Query { protected $attributes = [ 'name' => 'users', ]; public function type(): Type { return Type::nonNull(Type::listOf(Type::nonNull(GraphQL::type('User')))); } public function args(): array { return [ 'id' => [ 'name' => 'id', 'type' => Type::int(), ], 'email' => [ 'name' => 'email', 'type' => Type::string(), ] ]; } public function resolve($root, array $args, $context, ResolveInfo $resolveInfo, Closure $getSelectFields) { $query = User::query(); if (isset($args['id'])) { $query->where('id', $args['id']); } if (isset($args['email'])) { $query->where('email', $args['email']); } return $query->get(); } } ``` ```graphql # GraphQL query example query FetchUsers { users(id: 1) { id email name } } ``` ```bash # HTTP request example curl -X POST http://localhost/graphql \ -H "Content-Type: application/json" \ -d '{"query": "query FetchUsers { users(id: 1) { id email name } }"}' ``` ## Creating a Mutation Defining a mutation to modify data ```php <?php namespace App\GraphQL\Mutations; use Closure; use App\Models\User; use GraphQL\Type\Definition\Type; use GraphQL\Type\Definition\ResolveInfo; use Rebing\GraphQL\Support\Facades\GraphQL; use Rebing\GraphQL\Support\Mutation; class UpdateUserPasswordMutation extends Mutation { protected $attributes = [ 'name' => 'updateUserPassword' ]; public function type(): Type { return Type::nonNull(GraphQL::type('User')); } public function args(): array { return [ 'id' => [ 'name' => 'id', 'type' => Type::nonNull(Type::int()), 'rules' => ['required', 'exists:users,id'], ], 'password' => [ 'name' => 'password', 'type' => Type::nonNull(Type::string()), 'rules' => ['required', 'min:8'], ] ]; } public function resolve($root, array $args, $context, ResolveInfo $resolveInfo, Closure $getSelectFields) { $user = User::findOrFail($args['id']); $user->password = bcrypt($args['password']); $user->save(); return $user; } } ``` ```graphql # GraphQL mutation example mutation UpdatePassword { updateUserPassword(id: 1, password: "newsecurepass123") { id email } } ``` ```bash # HTTP request with mutation curl -X POST http://localhost/graphql \ -H "Content-Type: application/json" \ -d '{"query": "mutation { updateUserPassword(id: 1, password: \"newsecurepass123\") { id email } }"}' ``` ## Validation with Rules Implementing Laravel validation in queries and mutations ```php <?php namespace App\GraphQL\Mutations; use Closure; use App\Models\User; use GraphQL\Type\Definition\Type; use GraphQL\Type\Definition\ResolveInfo; use Rebing\GraphQL\Support\Facades\GraphQL; use Rebing\GraphQL\Support\Mutation; class UpdateUserEmailMutation extends Mutation { protected $attributes = [ 'name' => 'updateUserEmail' ]; public function type(): Type { return GraphQL::type('User'); } public function args(): array { return [ 'id' => [ 'name' => 'id', 'type' => Type::int(), ], 'email' => [ 'name' => 'email', 'type' => Type::string(), ] ]; } protected function rules(array $args = []): array { return [ 'id' => ['required', 'exists:users,id'], 'email' => ['required', 'email', 'unique:users,email'], ]; } public function validationErrorMessages(array $args = []): array { return [ 'email.required' => 'Please enter your email address', 'email.email' => 'Please enter a valid email address', 'email.unique' => 'This email address is already in use', ]; } public function resolve($root, array $args) { $user = User::find($args['id']); if (!$user) { return null; } $user->email = $args['email']; $user->save(); return $user; } } ``` ```json // Validation error response format { "data": { "updateUserEmail": null }, "errors": [ { "message": "validation", "extensions": { "validation": { "email": [ "This email address is already in use" ] } }, "locations": [ { "line": 1, "column": 20 } ] } ] } ``` ## Authorization on Queries and Mutations Implementing authorization logic to control access ```php <?php namespace App\GraphQL\Queries; use Closure; use GraphQL\Type\Definition\ResolveInfo; use GraphQL\Type\Definition\Type; use Illuminate\Support\Facades\Auth; use Rebing\GraphQL\Support\Facades\GraphQL; use Rebing\GraphQL\Support\Query; use App\Models\User; class UserQuery extends Query { protected $attributes = [ 'name' => 'user', ]; public function type(): Type { return GraphQL::type('User'); } public function args(): array { return [ 'id' => [ 'name' => 'id', 'type' => Type::nonNull(Type::int()), ], ]; } public function authorize($root, array $args, $ctx, ResolveInfo $resolveInfo = null, Closure $getSelectFields = null): bool { // Only allow users to query their own data or if they're admin return Auth::check() && (Auth::id() == $args['id'] || Auth::user()->is_admin); } public function getAuthorizationMessage(): string { return 'You are not authorized to view this user'; } public function resolve($root, array $args, $context, ResolveInfo $resolveInfo, Closure $getSelectFields) { return User::find($args['id']); } } ``` ```bash # Unauthorized request returns error curl -X POST http://localhost/graphql \ -H "Content-Type: application/json" \ -d '{"query": "{ user(id: 2) { id email } }"}' # Response: # { # "errors": [{ # "message": "You are not authorized to view this user" # }] # } ``` ## Field Privacy Controlling field visibility based on context ```php <?php namespace App\GraphQL\Types; use App\Models\User; use GraphQL\Type\Definition\Type; use Illuminate\Support\Facades\Auth; use Rebing\GraphQL\Support\Type as GraphQLType; class UserType extends GraphQLType { protected $attributes = [ 'name' => 'User', 'description' => 'A user', 'model' => User::class, ]; public function fields(): array { return [ 'id' => [ 'type' => Type::nonNull(Type::int()), 'description' => 'The id of the user' ], 'email' => [ 'type' => Type::string(), 'description' => 'The email of user', 'privacy' => function(array $args, $ctx): bool { // Only show email to the user themselves return Auth::check() && $args['id'] == Auth::id(); } ], 'public_profile' => [ 'type' => Type::string(), 'description' => 'Public profile information', ] ]; } } ``` ```graphql # When authenticated as user 1 query { user(id: 1) { id email # Will return email } } # When querying another user query { user(id: 2) { id email # Will return null due to privacy } } ``` ## Eager Loading with SelectFields Optimizing database queries to prevent N+1 problems ```php <?php namespace App\GraphQL\Queries; use Closure; use App\Models\User; use GraphQL\Type\Definition\ResolveInfo; use GraphQL\Type\Definition\Type; use Rebing\GraphQL\Support\Facades\GraphQL; use Rebing\GraphQL\Support\Query; use Rebing\GraphQL\Support\SelectFields; class UsersQuery extends Query { protected $attributes = [ 'name' => 'users', ]; public function type(): Type { return Type::listOf(GraphQL::type('User')); } public function resolve($root, array $args, $context, ResolveInfo $info, Closure $getSelectFields) { /** @var SelectFields $fields */ $fields = $getSelectFields(); $select = $fields->getSelect(); $with = $fields->getRelations(); return User::select($select)->with($with)->get(); } } ``` ```php <?php namespace App\GraphQL\Types; use App\Models\User; use GraphQL\Type\Definition\Type; use Rebing\GraphQL\Support\Facades\GraphQL; use Rebing\GraphQL\Support\Type as GraphQLType; class UserType extends GraphQLType { protected $attributes = [ 'name' => 'User', 'model' => User::class, ]; public function fields(): array { return [ 'id' => [ 'type' => Type::nonNull(Type::int()), ], 'profile' => [ 'type' => GraphQL::type('Profile'), 'description' => 'User profile', ], 'posts' => [ 'type' => Type::listOf(GraphQL::type('Post')), 'description' => 'User posts', 'always' => ['title', 'created_at'], ] ]; } } ``` ```graphql # This query will automatically eager load profile and posts query { users { id profile { name bio } posts { title created_at } } } ``` ## Pagination Support Implementing paginated queries for large datasets ```php <?php namespace App\GraphQL\Queries; use Closure; use App\Models\Post; use GraphQL\Type\Definition\ResolveInfo; use GraphQL\Type\Definition\Type; use Rebing\GraphQL\Support\Facades\GraphQL; use Rebing\GraphQL\Support\Query; class PostsQuery extends Query { public function type(): Type { return GraphQL::paginate('Post'); } public function resolve($root, array $args, $context, ResolveInfo $info, Closure $getSelectFields) { $fields = $getSelectFields(); return Post::with($fields->getRelations()) ->select($fields->getSelect()) ->paginate($args['limit'], ['*'], 'page', $args['page']); } } ``` ```graphql # Paginated query query { posts(limit: 10, page: 1) { data { id title body } total per_page current_page from to } } ``` ```json // Pagination response { "data": { "posts": { "data": [ {"id": 1, "title": "First Post", "body": "Content..."}, {"id": 2, "title": "Second Post", "body": "Content..."} ], "total": 25, "per_page": 10, "current_page": 1, "from": 1, "to": 10 } } } ``` ## File Upload Support Handling file uploads in GraphQL mutations ```php <?php namespace App\GraphQL\Mutations; use Closure; use GraphQL\Type\Definition\ResolveInfo; use GraphQL\Type\Definition\Type; use Rebing\GraphQL\Support\Facades\GraphQL; use Rebing\GraphQL\Support\Mutation; class UserProfilePhotoMutation extends Mutation { protected $attributes = [ 'name' => 'userProfilePhoto', ]; public function type(): Type { return GraphQL::type('User'); } public function args(): array { return [ 'user_id' => [ 'name' => 'user_id', 'type' => Type::nonNull(Type::int()), ], 'profilePicture' => [ 'name' => 'profilePicture', 'type' => GraphQL::type('Upload'), 'rules' => ['required', 'image', 'max:1500'], ], ]; } public function resolve($root, array $args, $context, ResolveInfo $resolveInfo, Closure $getSelectFields) { $file = $args['profilePicture']; $path = $file->store('profile-photos', 'public'); $user = User::findOrFail($args['user_id']); $user->profile_photo = $path; $user->save(); return $user; } } ``` ```javascript // JavaScript/Vue.js example with Axios const formData = new FormData(); formData.set('operations', JSON.stringify({ 'query': `mutation uploadPhoto($file: Upload!, $userId: Int!) { userProfilePhoto(user_id: $userId, profilePicture: $file) { id profile_photo } }`, 'variables': { 'userId': 1, 'file': null } })); formData.set('map', JSON.stringify({'file': ['variables.file']})); formData.append('file', fileInput.files[0]); const response = await axios.post('/graphql', formData, { headers: { 'Content-Type': 'multipart/form-data' } }); ``` ## Input Objects Creating complex input types for mutations ```php <?php namespace App\GraphQL\InputObject; use GraphQL\Type\Definition\Type; use Rebing\GraphQL\Support\InputType; class UserInput extends InputType { protected $attributes = [ 'name' => 'UserInput', 'description' => 'User input data' ]; public function fields(): array { return [ 'firstName' => [ 'name' => 'firstName', 'type' => Type::nonNull(Type::string()), 'rules' => ['required', 'max:50'], 'alias' => 'first_name', ], 'lastName' => [ 'name' => 'lastName', 'type' => Type::nonNull(Type::string()), 'rules' => ['required', 'max:50'], 'alias' => 'last_name', ], 'email' => [ 'name' => 'email', 'type' => Type::nonNull(Type::string()), 'rules' => ['required', 'email'], ], ]; } } ``` ```php <?php namespace App\GraphQL\Mutations; use Closure; use App\Models\User; use GraphQL\Type\Definition\Type; use GraphQL\Type\Definition\ResolveInfo; use Rebing\GraphQL\Support\Facades\GraphQL; use Rebing\GraphQL\Support\Mutation; class CreateUserMutation extends Mutation { protected $attributes = [ 'name' => 'createUser' ]; public function type(): Type { return GraphQL::type('User'); } public function args(): array { return [ 'input' => [ 'type' => Type::nonNull(GraphQL::type('UserInput')) ] ]; } public function resolve($root, array $args, $context, ResolveInfo $resolveInfo, Closure $getSelectFields) { $user = User::create($args['input']); return $user; } } ``` ```graphql # Using input objects mutation { createUser(input: { firstName: "John" lastName: "Doe" email: "john.doe@example.com" }) { id email } } ``` ## Resolver Middleware Creating custom middleware for queries and mutations ```php <?php namespace App\GraphQL\Middleware; use Closure; use GraphQL\Type\Definition\ResolveInfo; use Illuminate\Support\Facades\Log; use Rebing\GraphQL\Support\Middleware; class LogQueryMiddleware extends Middleware { public function handle($root, array $args, $context, ResolveInfo $info, Closure $next) { $startTime = microtime(true); Log::info('GraphQL Query Started', [ 'query' => $info->fieldName, 'args' => $args, ]); $result = $next($root, $args, $context, $info); $duration = microtime(true) - $startTime; Log::info('GraphQL Query Completed', [ 'query' => $info->fieldName, 'duration' => $duration, ]); return $result; } public function terminate($root, array $args, $context, ResolveInfo $info, $result): void { Log::debug('GraphQL Query Terminated', [ 'query' => $info->fieldName, 'result_count' => is_countable($result) ? count($result) : null, ]); } } ``` ```php <?php namespace App\GraphQL\Queries; use App\GraphQL\Middleware\LogQueryMiddleware; use Rebing\GraphQL\Support\Query; class UsersQuery extends Query { protected $middleware = [ LogQueryMiddleware::class, ]; // ... rest of query implementation } ``` ## Batching Multiple Requests Sending multiple queries/mutations in a single HTTP request ```json // Batched request [ { "query": "query { users { id email } }" }, { "query": "mutation { updateUserPassword(id: 1, password: \"newpass\") { id } }", "variables": {} }, { "query": "query GetPost($id: Int!) { post(id: $id) { title body } }", "variables": {"id": 5} } ] ``` ```bash # Batched HTTP request curl -X POST http://localhost/graphql \ -H "Content-Type: application/json" \ -d '[ {"query": "{ users { id email } }"}, {"query": "mutation { updateUserPassword(id: 1, password: \"newpass\") { id } }"} ]' ``` ```json // Batched response [ { "data": { "users": [ {"id": 1, "email": "user1@example.com"}, {"id": 2, "email": "user2@example.com"} ] } }, { "data": { "updateUserPassword": { "id": 1 } } } ] ``` ## Summary Laravel GraphQL provides a complete solution for building GraphQL APIs within Laravel applications, offering seamless integration with Laravel's ecosystem including Eloquent ORM, validation, authentication, and middleware. The package supports all core GraphQL features including queries, mutations, types, interfaces, unions, enums, and subscriptions, while adding Laravel-specific enhancements like automatic pagination types, file upload handling, and privacy controls. Developers can build type-safe APIs with minimal boilerplate through code generation commands and intuitive class-based definitions for all GraphQL components. The library excels at solving common API development challenges through features like SelectFields for automatic query optimization, built-in validation using Laravel's validator, resolver middleware for cross-cutting concerns, and support for multiple schemas with independent configurations. Whether building a simple REST alternative or a complex multi-tenant API with advanced authorization rules, Laravel GraphQL provides the tools and patterns necessary for maintainable, performant GraphQL implementations. The package's focus on developer experience, combined with comprehensive documentation and examples, makes it an ideal choice for Laravel developers looking to adopt GraphQL while maintaining familiar Laravel conventions and best practices.