Installation:
composer require optigov/eloquent-graphql
Annotate Models:
Add @property docblocks to your Eloquent models to define GraphQL fields. Example:
/**
* @property int $id
* @property string $name
* @property-read \Carbon\Carbon $created_at
*/
class Post {}
Register Schema:
Integrate the schema into your GraphQL server (e.g., webonyx/graphql-php):
use EloquentGraphQL\Services\EloquentGraphQLService;
$service = new EloquentGraphQLService();
$schema = new Schema([
'query' => $service->query()
->view(Post::class)
->all(Post::class)
->build(),
]);
First Query: Query your annotated model directly:
query {
posts {
id
name
}
}
@property and @property-read docblocks in your Eloquent models.EloquentGraphQLService is the core class for schema generation.Model Annotations:
@property for writable fields (e.g., name).@property-read for read-only fields (e.g., created_at).@property Author $author).@property Post[] $comments).Schema Registration:
view(Model::class): Exposes a single model query (e.g., post(id: 1)).all(Model::class): Exposes a collection query (e.g., posts).create(Model::class), update(Model::class), delete(Model::class).Relationship Handling:
belongsTo, hasMany, belongsToMany, etc., via annotations./**
* @property Author $author
* @property Post[] $comments
*/
class Post {}
Query:
query {
post(id: 1) {
author { name }
comments { title }
}
}
Pagination and Filtering:
cursor-based pagination (e.g., posts(first: 10)).posts(where: { name_contains: "Laravel" })).posts(orderBy: { field: "created_at", direction: DESC })).Integration with Laravel:
whereHas, orWhere).Custom Resolvers:
Override default resolvers by extending EloquentGraphQLService or using GraphQL’s resolver hooks.
Example:
$service->query()->view(Post::class)->customResolver('customField', fn($root) => $root->title . ' (Custom)');
Input Types:
Automatically generates input types for mutations (e.g., CreatePostInput).
Customize via annotations:
/**
* @property-write string $name
* @property-write string $content
*/
class Post {}
Performance:
Use with() in annotations to eager-load relationships:
/**
* @property Author $author
* @property-read Post[] $comments with="user"
*/
class Post {}
Annotation Syntax:
@property-read for non-writable fields (e.g., timestamps) will cause GraphQL errors.@property Author[] $authors when it’s a belongsTo) may break queries.Circular References:
Post ↔ Author with hasMany/belongsTo) can cause infinite recursion.@property-read and limit depth in queries or add @ignore to one side:
/**
* @property-read Author $author @ignore
*/
class Post {}
Pagination Quirks:
first vs. last).$service->query()->all(Post::class)->paginate(20, 'page');
Mutation Limitations:
create, update) may not be fully supported out of the box.Caching:
$schema = Cache::remember('graphql.schema', now()->addHours(1), fn() => $schema);
Schema Validation: Use GraphQL’s introspection to validate your schema:
query {
__schema {
types {
name
fields {
name
type {
name
}
}
}
}
}
Logs and Errors: Enable GraphQL error logging:
$schema->setErrorHandler(function ($error) {
Log::error($error->getMessage());
});
Annotation Validation: Run PHPStan or Psalm to catch annotation syntax errors early.
Custom Directives: Add GraphQL directives to models for dynamic behavior:
/**
* @property string $name @directive("uppercase")
*/
class Post {}
Then implement the directive logic in the resolver.
Plugin System:
Extend EloquentGraphQLService to add custom logic:
class CustomGraphQLService extends EloquentGraphQLService {
public function customMethod(Model $model) {
// Add custom GraphQL logic
}
}
Hybrid Schemas:
Combine with other GraphQL packages (e.g., rebing/graphql-laravel) for advanced features like subscriptions or custom scalars.
Testing: Use Laravel’s HTTP tests to validate GraphQL queries:
$response = $this->graphQL(['query' => '{ posts { id } }']);
$response->assertJson(['data' => ['posts' => [...]]);
How can I help you explore Laravel packages today?