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

Graphqlite Bundle Laravel Package

besmartand-pro/graphqlite-bundle

View on GitHub
Deep Wiki
Context7
## Getting Started

### Minimal Setup
1. **Install the Bundle**
   ```bash
   composer require besmartand-pro/graphqlite-bundle

Ensure BeSmartAnd\Pro\GraphQLiteBundle\GraphQLiteBundle::class is registered in config/bundles.php.

  1. Configure the Bundle Add a minimal graphqlite.yaml config under config/packages/besmartand_pro_graphqlite.yaml:

    graphqlite:
        schema:
            query: App\\GraphQL\\Query
            mutation: App\\GraphQL\\Mutation
    
  2. Define a Query Class Create a basic query resolver in src/GraphQL/Query.php:

    namespace App\GraphQL;
    
    use GraphQLite\Query\Query;
    use GraphQLite\Query\Type\Type;
    
    class Query extends Query
    {
        public function hello(): string
        {
            return 'world';
        }
    }
    
  3. Test the Endpoint Access /graphql with a query:

    query {
        hello
    }
    

First Use Case: Fetching Data

Use GraphQLite to expose a simple API endpoint for a Doctrine entity (e.g., User):

// src/GraphQL/Query.php
public function users(): array
{
    return $this->getDoctrine()->getRepository(User::class)->findAll();
}

Query:

query {
    users {
        id
        name
    }
}

Implementation Patterns

Schema Organization

  1. Modular Queries/Mutations Split logic into separate classes (e.g., UserQuery, PostMutation) and reference them in config:

    graphqlite:
        schema:
            query: ['App\GraphQL\UserQuery', 'App\GraphQL\PostQuery']
    
  2. Type System Define custom types (e.g., UserType) for complex responses:

    use GraphQLite\Query\Type\Type;
    
    class UserType extends Type
    {
        public function getType(): string
        {
            return 'User';
        }
    
        public function getFields(): array
        {
            return [
                'id' => fn(User $user) => $user->getId(),
                'email' => fn(User $user) => $user->getEmail(),
            ];
        }
    }
    

Integration with Symfony

  1. Dependency Injection Inject services (e.g., UserRepository) into resolvers:

    public function __construct(private UserRepository $userRepository) {}
    
    public function user(int $id): ?User
    {
        return $this->userRepository->find($id);
    }
    
  2. Authentication Use Symfony’s security component to protect queries:

    use Symfony\Component\Security\Core\Security;
    
    public function __construct(private Security $security) {}
    
    public function me(): ?User
    {
        return $this->security->getUser();
    }
    
  3. Validation Validate input arguments with Symfony’s Validator:

    use Symfony\Component\Validator\Validator\ValidatorInterface;
    
    public function createUser(string $name, string $email, ValidatorInterface $validator)
    {
        $user = new User($name, $email);
        $errors = $validator->validate($user);
        if (count($errors)) {
            throw new \RuntimeException('Validation failed');
        }
        // Save user...
    }
    

Performance Patterns

  1. DataLoader for N+1 Queries Use GraphQLite\DataLoader\DataLoader to batch-load related entities:

    public function posts(): array
    {
        $posts = $this->postRepository->findAll();
        $userIds = array_map(fn($post) => $post->getUserId(), $posts);
        $users = $this->dataLoader->loadMany($userIds, User::class);
        return array_map(fn($post) => [
            'post' => $post,
            'author' => $users[$post->getUserId()],
        ], $posts);
    }
    
  2. Caching Cache query results with Symfony’s cache system:

    use Symfony\Contracts\Cache\CacheInterface;
    
    public function __construct(private CacheInterface $cache) {}
    
    public function trendingPosts(): array
    {
        return $this->cache->get('trending_posts', function() {
            return $this->postRepository->findTrending();
        }, null, ['graphql']);
    }
    

Gotchas and Tips

Common Pitfalls

  1. Schema Registration

    • Issue: Forgetting to register the query/mutation class in graphqlite.yaml.
    • Fix: Verify the config and clear cache (php bin/console cache:clear).
  2. Circular Dependencies

    • Issue: Resolvers referencing each other (e.g., User resolver calling Post resolver which calls User).
    • Fix: Use DataLoader or flatten the response structure.
  3. Type Mismatches

    • Issue: Returning unexpected types (e.g., null when a non-nullable field is expected).
    • Fix: Annotate fields with @nonnull in GraphQL schema or handle null cases explicitly.
  4. Doctrine Lazy Loading

    • Issue: Accessing lazy-loaded properties in resolvers throws LazyLoadingException.
    • Fix: Use ->getId() or ->getOneOrNewReference() to trigger loading, or fetch eager data.

Debugging Tips

  1. Enable GraphQL Playground Install the graphql-playground package and configure it in config/packages/graphqlite.yaml:

    graphqlite:
        playground: true
    

    Access /graphql for an interactive IDE.

  2. Logging Queries Enable debug logging in config/packages/monolog.yaml:

    handlers:
        graphql:
            type: stream
            path: "%kernel.logs_dir%/graphql.log"
            level: debug
            channels: ["graphql"]
    
  3. Validation Errors

    • Check the errors field in the response for validation failures.
    • Use GraphQLite\Query\Exception\ValidationException to throw custom errors:
      throw new ValidationException('Invalid input', ['field' => 'Invalid value']);
      

Extension Points

  1. Custom Directives Extend GraphQLite with custom directives (e.g., @auth):

    use GraphQLite\Query\Directive\Directive;
    
    class AuthDirective extends Directive
    {
        public function getName(): string { return 'auth'; }
        public function getLocations(): array { return [self::QUERY, self::MUTATION]; }
    }
    
  2. Middleware Add middleware to modify requests/responses:

    use GraphQLite\Query\Middleware\Middleware;
    
    class LoggingMiddleware implements Middleware
    {
        public function handle(Request $request, callable $next): Response
        {
            \Log::info('GraphQL request', ['query' => $request->getQuery()]);
            return $next($request);
        }
    }
    

    Register in config:

    graphqlite:
        middleware: ['App\GraphQL\LoggingMiddleware']
    
  3. Subscriptions Use GraphQLite\Query\Subscription\Subscription for real-time updates (requires symfony/ux-live-component or similar):

    class Subscription extends \GraphQLite\Query\Subscription\Subscription
    {
        public function newPost(): \Generator
        {
            yield from $this->postRepository->getNewPostStream();
        }
    }
    

Configuration Quirks

  1. Autowiring Resolvers Ensure resolvers are autowireable by:

    • Using constructor injection.
    • Avoiding static methods (unless wrapped in a service).
  2. Schema Caching Disable caching during development:

    graphqlite:
        schema:
            cache: false
    
  3. Custom Scalar Types Register custom scalars (e.g., DateTime) in config:

    graphqlite:
        scalars:
            DateTime: App\GraphQL\Scalar\DateTimeScalar
    

---
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.
emuniq/filament-browser-notifications
syriable/filament-translator
hungnm28/livewire-form
wenprise/eloquent
crudly/encrypted
fadion/bouncy
cuci/prototurk-sdk
gos/pubsub-router-bundle
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui