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

Apip Graphql Validator Formatter Laravel Package

cvek/apip-graphql-validator-formatter

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation Add the package via Composer:

    composer require cvek/apip-graphql-validator-formatter
    

    Publish the config (if needed):

    php artisan vendor:publish --provider="Cvek\GraphQLValidatorFormatter\GraphQLValidatorFormatterServiceProvider"
    
  2. Basic Usage Register the formatter in your API Platform GraphQL configuration (config/graphql.php):

    'validation' => [
        'error_formatter' => \Cvek\GraphQLValidatorFormatter\ErrorFormatter::class,
    ],
    
  3. First Use Case Trigger a GraphQL mutation with invalid input (e.g., missing required field). The package will automatically format validation errors into a structured JSON response, improving client-side error handling.


Implementation Patterns

Workflow Integration

  1. Validation Error Handling

    • Use the formatter alongside API Platform’s built-in validation (e.g., Symfony Validator).
    • Example mutation with validation:
      mutation CreateUser($name: String!, $email: String!) {
        createUser(input: { name: $name, email: $email }) {
          errors {
            field
            message
            code
          }
        }
      }
      
    • Invalid input returns:
      {
        "errors": [
          {
            "field": "email",
            "message": "This value should not be blank.",
            "code": "NOT_BLANK"
          }
        ]
      }
      
  2. Custom Error Mapping Extend the formatter to map Symfony validation errors to custom GraphQL error types:

    // app/GraphQL/ErrorFormatter.php
    use Cvek\GraphQLValidatorFormatter\ErrorFormatter;
    
    class CustomErrorFormatter extends ErrorFormatter {
        protected function formatError(ConstraintViolationInterface $error) {
            return [
                'field' => $error->getPropertyPath(),
                'message' => $this->translateMessage($error),
                'code' => $error->getConstraint()->getName(),
                'custom_field' => 'your_value' // Add custom data
            ];
        }
    }
    

    Register it in config/graphql.php:

    'validation' => [
        'error_formatter' => \App\GraphQL\CustomErrorFormatter::class,
    ],
    
  3. Combining with API Platform Filters Use the formatter with API Platform’s validation_groups or custom constraints:

    # config/validator/validation.yaml
    App\Entity\User:
      constraints:
        - Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity: { fields: email, message: "Email already taken." }
    

Integration Tips

  • Testing: Mock validation errors in PHPUnit to verify formatter output:
    $error = $this->createMock(ConstraintViolationInterface::class);
    $error->method('getPropertyPath')->willReturn('email');
    $error->method('getMessage')->willReturn('Invalid email.');
    $formatter = new ErrorFormatter();
    $result = $formatter->format($error); // Test structured output
    
  • Frontend Integration: Use the formatted errors in React/Vue to show user-friendly messages:
    // Example: Display errors in a form
    errors.forEach(error => {
      console.log(`Field: ${error.field}, Message: ${error.message}`);
    });
    

Gotchas and Tips

Pitfalls

  1. Configuration Overrides

    • If the formatter isn’t working, ensure it’s registered in config/graphql.php. API Platform may override settings in config/packages/api_platform.yaml.
    • Fix: Explicitly set the formatter in config/graphql.php after other configurations.
  2. Nested Validation Errors

    • The package may not handle nested objects (e.g., input: { user: { name: "" } }) by default.
    • Workaround: Extend ErrorFormatter to recursively process nested violations:
      public function format(ConstraintViolationListInterface $errors) {
          $formatted = [];
          foreach ($errors as $error) {
              $path = explode('.', $error->getPropertyPath());
              $formatted = $this->buildNestedErrors($formatted, $path, $error);
          }
          return $formatted;
      }
      
      protected function buildNestedErrors(array $errors, array $path, ConstraintViolationInterface $error) {
          $current = &$errors;
          foreach ($path as $key) {
              if (!isset($current[$key])) {
                  $current[$key] = [];
              }
              $current = &$current[$key];
          }
          $current[] = $this->formatSingleError($error);
          return $errors;
      }
      
  3. Translation Issues

    • Error messages rely on Symfony’s translator. If messages appear untranslated, ensure:
      • The translator service is configured in Laravel.
      • Validation messages are loaded (e.g., app/Resources/translations/validation.en.yaml).
  4. Performance

    • Avoid heavy processing in formatError(). For large payloads, lazy-load error details or use caching.

Debugging

  • Log Raw Errors: Temporarily log unformatted errors to debug:
    // In ErrorFormatter
    public function format(ConstraintViolationListInterface $errors) {
        \Log::debug('Raw errors:', $errors->getIterator()->getArrayCopy());
        return parent::format($errors);
    }
    
  • Check API Platform Events: Listen to api_platform.validation.error events to inspect validation failures:
    use Symfony\Component\EventDispatcher\EventSubscriberInterface;
    use ApiPlatform\Core\EventListener\ValidationErrorListener;
    
    class ValidationSubscriber implements EventSubscriberInterface {
        public static function getSubscribedEvents() {
            return [
                ValidationErrorListener::EVENT_NAME => 'onValidationError',
            ];
        }
    
        public function onValidationError(ValidationErrorEvent $event) {
            \Log::debug('Validation errors:', $event->getErrors());
        }
    }
    

Extension Points

  1. Custom Error Codes Add custom error codes to constraints and map them in the formatter:

    # config/validator/validation.yaml
    App\Entity\User:
      constraints:
        - App\Validator\Constraints\CustomConstraint: { code: "CUSTOM_ERROR", message: "Custom error message." }
    
    // In ErrorFormatter
    protected function formatError(ConstraintViolationInterface $error) {
        if ($error->getConstraint()->getName() === 'custom_constraint') {
            return [
                'field' => $error->getPropertyPath(),
                'message' => $error->getMessage(),
                'code' => 'CUSTOM_ERROR',
                'metadata' => ['custom_field' => 'value'] // Extend with custom data
            ];
        }
        return parent::formatError($error);
    }
    
  2. Localization Override error messages per locale by extending the formatter:

    protected function translateMessage(ConstraintViolationInterface $error) {
        $translator = app('translator');
        return $translator->trans(
            $error->getMessage(),
            [],
            'validation'
        );
    }
    
  3. GraphQL Directives Use the formatter with GraphQL directives to conditionally apply validation:

    directive @validate(input: String!) on FIELD_DEFINITION
    
    type Mutation {
        createUser(input: UserInput!): User @validate(input: "required")
    }
    
    • Implementation: Create a custom directive resolver to trigger validation.
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