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

webonyx/graphql-php

webonyx/graphql-php is a GraphQL server implementation for PHP, following the official GraphQL specification and modeled after graphql-js. Build schemas, execute queries, validate documents, and extend via types, resolvers, and tooling for production APIs.

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.php):

    use GraphQL\Type\Definition\Type;
    use GraphQL\Schema\SchemaConfig;
    use GraphQL\Type\Definition\ObjectType;
    use GraphQL\Type\Definition\FieldDefinition;
    
    $queryType = new ObjectType([
        'name' => 'Query',
        'fields' => [
            'hello' => new FieldDefinition([
                'type' => Type::string(),
                'resolve' => fn() => 'World',
            ]),
        ],
    ]);
    
    return new SchemaConfig([
        'query' => $queryType,
    ]);
    
  3. Create a GraphQL controller (e.g., app/Http/Controllers/GraphQLController.php):

    use GraphQL\GraphQL;
    use GraphQL\Executor\ExecutionResult;
    use GraphQL\Validator\DocumentValidator;
    
    class GraphQLController extends Controller
    {
        public function execute(string $query, array $variables = []): array
        {
            $schema = (new Schema())->getSchema();
            $document = GraphQL::parse($query);
            $validator = new DocumentValidator();
            $validationErrors = $validator->validate($schema, $document);
    
            if (!empty($validationErrors)) {
                return ['errors' => $validationErrors];
            }
    
            $result = GraphQL::execute(
                $schema,
                $document,
                null,
                null,
                $variables
            );
    
            return $result->toArray();
        }
    }
    
  4. Add a route (routes/web.php):

    Route::post('/graphql', [GraphQLController::class, 'execute']);
    
  5. Test with a query:

    query {
      hello
    }
    

First Use Case: Querying Data

  • Use the controller to execute GraphQL queries directly from Laravel routes or API endpoints.
  • Example query:
    query GetUser($id: ID!) {
      user(id: $id) {
        id
        name
        email
      }
    }
    

Implementation Patterns

Schema Design Patterns

  1. Type Composition:

    • Use ObjectType, InterfaceType, and UnionType to model domain entities.
    • Example:
      $userType = new ObjectType([
          'name' => 'User',
          'fields' => [
              'id' => Type::id(),
              'name' => Type::string(),
              'posts' => new FieldDefinition([
                  'type' => new ListOfType(Type::string()),
                  'resolve' => fn($root) => ['Post 1', 'Post 2'],
              ]),
          ],
      ]);
      
  2. Input Types:

    • Define input types for mutations with InputObjectType.
    • Example:
      $createUserInput = new InputObjectType([
          'name' => 'CreateUserInput',
          'fields' => [
              'name' => Type::string(),
              'email' => Type::string(),
          ],
      ]);
      
  3. Lazy Loading:

    • Use callables for root types to defer schema initialization:
      $schemaConfig = new SchemaConfig([
          'query' => fn() => $queryType,
          'mutation' => fn() => $mutationType,
      ]);
      

Resolver Patterns

  1. Field Resolvers:

    • Resolve fields using closures or class methods.
    • Example:
      'resolve' => fn($root, $args, $context, $info) => User::find($args['id']),
      
  2. Context Injection:

    • Pass Laravel services (e.g., Auth, DB) via the context:
      $result = GraphQL::execute($schema, $document, null, [
          'auth' => auth(),
          'db' => app('db'),
      ]);
      
  3. DataLoader Integration:

    • Use GraphQL\Executor\Promise\Adapter\DataLoaderAdapter for batch loading:
      $promiseAdapter = new DataLoaderAdapter();
      $result = GraphQL::execute($schema, $document, null, null, [], $promiseAdapter);
      

Query Execution Patterns

  1. Batch Execution:

    • Execute multiple queries in a single request using GraphQL::batchExecute() (for subscriptions or multi-query endpoints).
  2. Validation:

    • Customize validation rules via GraphQL\Validator\Rule\RuleSet:
      $validator = new DocumentValidator();
      $validator->addRule(new QueryComplexityRule(1000));
      
  3. Error Handling:

    • Catch execution errors and format them for clients:
      try {
          $result = GraphQL::execute($schema, $document, null, null, $variables);
      } catch (\Exception $e) {
          return ['errors' => [$e->getMessage()]];
      }
      

Integration with Laravel

  1. Middleware:

    • Add GraphQL-specific middleware (e.g., auth, CORS):
      Route::middleware(['auth:sanctum'])->post('/graphql', [GraphQLController::class, 'execute']);
      
  2. Service Providers:

    • Bind the schema to the container for dependency injection:
      $this->app->singleton(Schema::class, fn() => new Schema());
      
  3. Testing:

    • Use Laravel's HTTP tests to simulate GraphQL requests:
      $response = $this->post('/graphql', [
          'query' => '{ hello }',
      ]);
      $response->assertJson(['data' => ['hello' => 'World']]);
      

Gotchas and Tips

Common Pitfalls

  1. Circular Dependencies:

    • Avoid circular references in type definitions (e.g., User referencing Post which references User). Use resolveType for unions/interfaces to break cycles.
  2. Null Handling:

    • Non-null fields (Type::nonNull(Type::string())) must always return a value. Use null or null checks carefully in resolvers.
  3. Performance:

    • Deeply nested queries can cause stack overflows. Use QueryComplexityRule to limit query depth:
      $validator->addRule(new QueryComplexityRule(1000));
      
  4. Type Safety:

    • Ensure resolver return types match the field's GraphQL type. Use @var annotations for IDE support:
      /** @return string */
      'resolve' => fn() => 'value',
      
  5. Deprecated Features:

    • Avoid Type::overrideStandardTypes() (deprecated in v15.31.0). Use per-schema scalar overrides instead:
      $schemaConfig = new SchemaConfig([
          'types' => [
              Type::string() => new CustomStringType(),
          ],
      ]);
      

Debugging Tips

  1. Validation Errors:

    • Enable detailed validation errors by inspecting the DocumentValidator output:
      $validationErrors = $validator->validate($schema, $document);
      dd($validationErrors); // Debug validation issues
      
  2. Execution Errors:

    • Use GraphQL::execute() with a custom error formatter:
      $result = GraphQL::execute($schema, $document, null, null, $variables);
      if ($result->hasErrors()) {
          dd($result->getErrors()); // Inspect execution errors
      }
      
  3. Query Complexity:

    • Enable complexity logging to identify expensive queries:
      $validator->addRule(new QueryComplexityRule(1000, fn($complexity) => logger()->debug("Query complexity: {$complexity}")));
      
  4. Introspection:

    • Disable introspection in production for security:
      $schemaConfig = new SchemaConfig([
          'query' => $queryType,
          'introspection' => false, // Disable introspection
      ]);
      

Extension Points

  1. Custom Directives:

    • Implement custom directives using GraphQL\Type\Definition\Directive:
      $authDirective = new Directive([
          'name' => 'auth',
          'locations' => [Directive::FIELD_DEFINITION],
          'args' => [],
      ]);
      
  2. Scalar Extensions:

    • Extend built-in scalars (e.g., Type::string()) for custom validation:
      class CustomStringType extends ScalarType {
          public function serialize($value) { /* ... */ }
          public function parseValue($value) { /* ... */ }
          public function parseLiteral($valueNode, ?array $variables = null) { /* ... */ }
      }
      
  3. Execution Middleware:

    • Add middleware to the executor pipeline:
      $executor = new ExecutionStrategy();
      $executor->addMiddleware(new CustomMiddleware());
      
  4. Schema Extender:

    • Dynamically
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.
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
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope