Weave Code
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 Php Laravel Package

pixelandtonic/graphql-php

PHP implementation of the GraphQL specification (based on graphql-js). Build schemas, execute queries, and add custom types, fields, and resolvers. Install via Composer and explore full docs and ready-to-run examples.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup in Laravel

  1. Install the package:

    composer require webonyx/graphql-php
    
  2. Define a basic schema (e.g., app/GraphQL/schema.graphql):

    type Query {
      hello: String
    }
    
  3. Create a resolver (e.g., app/GraphQL/Resolvers/Query.php):

    namespace App\GraphQL\Resolvers;
    
    use GraphQL\Type\Definition\ResolveInfo;
    use GraphQL\Type\Definition\Type;
    
    class Query {
        public function hello() {
            return 'Hello, Laravel + GraphQL!';
        }
    }
    
  4. Set up the schema in a Laravel service provider (e.g., AppServiceProvider):

    use GraphQL\GraphQL;
    use GraphQL\Type\Definition\Type;
    use GraphQL\Schema;
    use GraphQL\Type\Definition\ObjectType;
    
    public function boot() {
        $query = new ObjectType([
            'name' => 'Query',
            'fields' => [
                'hello' => [
                    'type' => Type::string(),
                    'resolve' => fn() => (new \App\GraphQL\Resolvers\Query())->hello(),
                ],
            ],
        ]);
    
        $schema = new Schema(['query' => $query]);
        app()->singleton('graphql.schema', fn() => $schema);
    }
    
  5. Create a route (e.g., routes/web.php):

    use GraphQL\Server\ServerConfig;
    use GraphQL\Server\StandardServer;
    
    Route::post('/graphql', function () {
        $schema = app('graphql.schema');
        $config = new ServerConfig();
        $server = new StandardServer($schema, $config);
        return $server->executePsrRequest($_SERVER, $_GET, $_POST);
    });
    
  6. Test with a GraphQL client (e.g., Postman or Apollo Studio):

    query {
      hello
    }
    

First Use Case: Querying Data

Use the package to expose Laravel Eloquent models as GraphQL types. For example:

// Define a UserType
$userType = new ObjectType([
    'name' => 'User',
    'fields' => [
        'id' => ['type' => Type::id()],
        'name' => ['type' => Type::string()],
        'email' => ['type' => Type::string()],
    ],
]);

// Resolve fields dynamically
$schema = new Schema([
    'query' => new ObjectType([
        'name' => 'Query',
        'fields' => [
            'user' => [
                'type' => $userType,
                'args' => [
                    'id' => ['type' => Type::id()],
                ],
                'resolve' => function ($root, $args) {
                    return \App\Models\User::find($args['id']);
                },
            ],
        ],
    ]),
]);

Implementation Patterns

Schema Definition

Using Schema Definition Language (SDL)

Define schemas in .graphql files and load them dynamically:

use GraphQL\Type\Definition\Type;
use GraphQL\Schema;
use GraphQL\Type\Definition\ObjectType;

$schemaConfig = [
    'types' => [
        'Query' => [
            'fields' => [
                'posts' => [
                    'type' => Type::listOf($postType),
                    'resolve' => fn() => \App\Models\Post::all(),
                ],
            ],
        ],
    ],
];

$schema = new Schema($schemaConfig);

Lazy Loading Types

For large schemas, use lazy loading to improve performance:

use GraphQL\Type\Definition\TypeResolver;
use GraphQL\Type\Definition\TypeResolverInterface;

class LazyTypeResolver implements TypeResolverInterface {
    public function resolve($typeName) {
        if ($typeName === 'Post') {
            return $this->loadPostType();
        }
        return null;
    }

    private function loadPostType() {
        // Load and return PostType dynamically
    }
}

$schemaConfig = [
    'typeResolvers' => [new LazyTypeResolver()],
];

Resolvers

Class-Based Resolvers

Organize resolvers into classes for better maintainability:

class PostResolver {
    public function getPosts() {
        return \App\Models\Post::all();
    }

    public function getPost($root, $args) {
        return \App\Models\Post::find($args['id']);
    }
}

// In schema definition:
'posts' => [
    'type' => Type::listOf($postType),
    'resolve' => fn() => (new PostResolver())->getPosts(),
],

Closure-Based Resolvers

Use closures for simple or one-off resolvers:

'user' => [
    'type' => $userType,
    'args' => ['id' => ['type' => Type::id()]],
    'resolve' => function ($root, $args) {
        return \App\Models\User::find($args['id']);
    },
],

Input Types and Mutations

Input Types for Mutations

Define input types for mutations to validate incoming data:

$createUserInputType = new InputObjectType([
    'name' => 'CreateUserInput',
    'fields' => [
        'name' => ['type' => Type::nonNull(Type::string())],
        'email' => ['type' => Type::nonNull(Type::string())],
    ],
]);

$schemaConfig = [
    'mutation' => new ObjectType([
        'name' => 'Mutation',
        'fields' => [
            'createUser' => [
                'type' => $userType,
                'args' => [
                    'input' => ['type' => new GraphQLNonNull($createUserInputType)],
                ],
                'resolve' => function ($root, $args) {
                    return \App\Models\User::create($args['input']);
                },
            ],
        ],
    ]),
];

Integration with Laravel

Dependency Injection

Inject Laravel services (e.g., repositories, HTTP clients) into resolvers:

use Illuminate\Support\Facades\Http;

class ExternalApiResolver {
    public function __construct(private Http $http) {}

    public function fetchData() {
        return $this->http->get('https://api.example.com/data')->json();
    }
}

// Bind in Laravel service provider:
app()->bind(\App\GraphQL\Resolvers\ExternalApiResolver::class, function ($app) {
    return new \App\GraphQL\Resolvers\ExternalApiResolver($app['http']);
});

Authentication and Authorization

Use Laravel middleware to protect GraphQL endpoints:

Route::middleware(['auth:sanctum'])->post('/graphql', function () {
    $schema = app('graphql.schema');
    $config = new ServerConfig();
    $server = new StandardServer($schema, $config);
    return $server->executePsrRequest($_SERVER, $_GET, $_POST);
});

Caching Responses

Cache GraphQL query results using Laravel's cache:

use Illuminate\Support\Facades\Cache;

$schemaConfig = [
    'queryCache' => function ($query, $variables) {
        return Cache::remember("graphql:{$query}", 60, fn() => null);
    },
    'queryCacheStore' => function ($query, $variables, $result) {
        Cache::put("graphql:{$query}", $result, 60);
    },
];

Gotchas and Tips

Common Pitfalls

Strict Scalar Coercion

  • Issue: The package enforces strict scalar type coercion (e.g., "false" as a string won't coerce to false).
  • Fix: Ensure client input matches expected types. Use Type::nonNull() for required fields.
    'email' => ['type' => Type::nonNull(Type::string())],
    

Debugging Resolvers

  • Issue: Resolvers may silently fail or return unexpected data.
  • Tip: Use DebugFlag to expose detailed errors in development:
    $config = new ServerConfig([
        'debugFlag' => DebugFlag::INCLUDE_DEBUG_MESSAGE | DebugFlag::INCLUDE_TRACE,
    ]);
    

Circular Dependencies

  • Issue: Circular references in resolvers can cause infinite loops.
  • Fix: Use DataLoader for batching and caching:
    use GraphQL\Executor\Promise\Adapter\SyncPromise;
    use GraphQL\Executor\Promise\Promise;
    use GraphQL\Executor\Promise\PromiseAdapter;
    
    $promiseAdapter = new PromiseAdapter();
    $dataLoader = new DataLoader(fn($ids) => \App\Models\User::whereIn('id', $ids)->get());
    

Performance with Large Schemas

  • Issue: Large schemas can slow down query parsing.
  • Tip: Use lazy loading or split schemas into smaller modules.

Debugging Tips

Query Complexity

  • Tip: Enable query complexity analysis to detect expensive queries:
    $schemaConfig = [
        'query
    
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.
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle