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 Symfony Validator Bridge Laravel Package

thecodingmachine/graphqlite-symfony-validator-bridge

Bridge between GraphQLite and Symfony Validator: validate GraphQL inputs and arguments using Symfony constraints, returning validation errors in GraphQL responses. Integrates with GraphQLite’s validation features for Symfony-based projects.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package in your Laravel project:

    composer require thecodingmachine/graphqlite-symfony-validator-bridge
    
  2. Register the bridge in your GraphQLite schema configuration:

    use TheCodingMachine\GraphQLite\Validation\SymfonyValidatorBridge;
    use Symfony\Component\Validator\Validator\ValidatorInterface;
    
    // In your GraphQLite schema builder
    $validator = app(ValidatorInterface::class); // Laravel's built-in validator
    $schema->setValidator(new SymfonyValidatorBridge($validator));
    
  3. First use case: Validate a GraphQL mutation input with Symfony constraints.

    use Symfony\Component\Validator\Constraints as Assert;
    
    #[Assert\NotBlank]
    #[Assert\Email]
    private ?string $email;
    

Where to Look First

  • GraphQLite Validation Docs – Official guide on integrating validation.
  • Symfony Validator ConstraintsSymfony Docs for constraint reference.
  • Laravel’s Validator – If using Laravel’s built-in validator, ensure it’s properly bound to the ValidatorInterface.

Implementation Patterns

Common Workflows

1. Input Validation for Mutations

  • Use Symfony constraints on GraphQL input types to validate mutation payloads.
// GraphQL Input Type
#[GraphQLInputType]
class CreateUserInput {
    #[Assert\NotBlank]
    #[Assert\Length(min: 3, max: 50)]
    public string $name;

    #[Assert\Email]
    public ?string $email = null;
}

2. Reusing Existing Laravel Validation Logic

  • Leverage Laravel’s validation rules by converting them to Symfony constraints.
// Example: Convert Laravel's 'required|email' to Symfony
#[Assert\NotBlank]
#[Assert\Email]
private ?string $email;

3. Validation Groups

  • Use Symfony’s validation groups for conditional validation (e.g., Default, Create, Update).
$schema->setValidator(
    new SymfonyValidatorBridge($validator, ['Default', 'Create'])
);

4. Custom Validation Logic

  • Extend Symfony’s Constraint class for complex rules.
use Symfony\Component\Validator\Constraint;

class UniqueUsername extends Constraint {
    public string $message = 'This username is already taken.';
}
  • Apply it to your GraphQL input:
#[UniqueUsername]
private ?string $username;

5. Error Handling

  • Customize error responses by extending the bridge or using GraphQLite’s error formatting.
$schema->setErrorFormatter(function (ValidationException $e) {
    return [
        'errors' => array_map(function ($error) {
            return [
                'message' => $error->getMessage(),
                'path' => $error->getPropertyPath(),
            ];
        }, $e->getErrors())
    ];
});

Integration Tips

Laravel-Specific Tips

  1. Service Provider Setup Ensure the Symfony Validator is bound to Laravel’s container:

    // In AppServiceProvider
    public function register() {
        $this->app->extend(\Symfony\Component\Validator\Validator\ValidatorInterface::class,
            function ($app, $validator) {
                return $validator;
            });
    }
    
  2. Testing Validations Use Laravel’s testing helpers to assert validation errors:

    public function test_user_creation_validation() {
        $response = $this->post('/graphql', [
            'query' => 'mutation { createUser(input: { name: "", email: "invalid" }) }'
        ]);
    
        $response->assertJsonValidationErrors([
            'name' => ['This value should not be blank.'],
            'email' => ['This value is not a valid email address.']
        ]);
    }
    
  3. Performance Optimization

    • Cache the validator instance if using it across multiple requests:
    $validator = Cache::remember('graphql.validator', now()->addHours(1), function () {
        return app(ValidatorInterface::class);
    });
    
  4. Dynamic Validation Rules Use Symfony’s Callback constraint for dynamic validation:

    #[Assert\Callback]
    public function validate(ExecutionContextInterface $context, $payload) {
        if ($payload->email === 'admin@example.com') {
            $context->buildViolation('Admin email is restricted.')
                    ->atPath('email')
                    ->addViolation();
        }
    }
    

Gotchas and Tips

Pitfalls

  1. PHP Version Mismatch

    • Issue: Attributes (e.g., #[Assert\Email]) require PHP 8+. If using PHP 7.x, fall back to YAML/XML constraints.
    • Fix: Use validator: constraints in config/validation.yaml:
      App\GraphQL\Types\CreateUserInput:
          constraints:
              - NotBlank: { fields: name }
              - Email: { fields: email }
      
  2. Circular Dependencies

    • Issue: If your GraphQL types reference each other (e.g., User has Address, Address has User), Symfony’s validator may throw circular reference errors.
    • Fix: Use ValidationBuilder to exclude circular references:
      $validator = $this->validator->withRootConstraints();
      
  3. Laravel’s Validator vs. Symfony’s Validator

    • Issue: Laravel’s Validator facade is not the same as Symfony’s ValidatorInterface. Directly inject ValidatorInterface to avoid confusion.
    • Fix:
      $validator = app(\Symfony\Component\Validator\Validator\ValidatorInterface::class);
      
  4. Validation Overhead

    • Issue: Heavy validation constraints may slow down GraphQL queries.
    • Fix:
      • Use validation groups to limit constraints during queries.
      • Disable validation for non-critical fields (e.g., queries vs. mutations).
  5. Error Message Localization

    • Issue: Symfony’s default error messages may not match your app’s language.
    • Fix: Configure translation in config/validator.php:
      'translation_domain' => 'validators',
      

Debugging Tips

  1. Enable Debug Mode Symfony’s validator provides detailed errors in debug mode:

    $validator->setDebug(true);
    
  2. Log Validation Errors Extend the bridge to log errors for debugging:

    $schema->setValidator(new class($validator) extends SymfonyValidatorBridge {
        public function validate($data, array $groups = null) {
            try {
                return parent::validate($data, $groups);
            } catch (\Exception $e) {
                \Log::error('Validation failed: ' . $e->getMessage());
                throw $e;
            }
        }
    });
    
  3. Test Constraints Isolated Use Symfony’s Validator directly to test constraints before integrating with GraphQLite:

    $validator = app(ValidatorInterface::class);
    $errors = $validator->validate($inputData, null, ['Default']);
    
  4. Check for Deprecated Constraints

    • Symfony occasionally deprecates constraints. Update your code when using:
      • @Assert\Email (use @Assert\Email from symfony/validator).
      • Custom constraints may need updates for new Symfony versions.

Extension Points

  1. Custom Constraint Validators Extend Symfony’s ConstraintValidatorInterface for complex logic:

    use Symfony\Component\Validator\Constraint;
    use Symfony\Component\Validator\ConstraintValidator;
    
    class UniqueUsernameValidator extends ConstraintValidator {
        public function validate($value, Constraint $constraint) {
            if (User::where('username', $value)->exists()) {
                $this->context->buildViolation($constraint->message)
                    ->addViolation();
            }
        }
    }
    
  2. Override Error Formatting Customize how validation errors are returned in GraphQL responses:

    $schema->setErrorFormatter(function (ValidationException $e) {
        return [
            'errors' => array_map(function ($error) {
                return [
                    'message' => __($error->getMessage()),
                    'path' => explode('.', $error->getPropertyPath()),
                    'code' => $error->getCode(),
                ];
            }, $e->getErrors())
        ];
    });
    
  3. Integrate with Laravel’s Form Requests Reuse Laravel’s FormRequest validation logic in GraphQL:

    use Illuminate\Validation\Rule;
    
    #[Assert\NotBlank]
    #[Assert\Length(min: 8)]
    #[Assert\Regex('/^(?=.*[A-Z])(?=.*\d).+$/')] // At least 1 uppercase and 1 digit
    private ?string $password;
    
  4. Dynamic Constraint Loading

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