Class: GraphQL::StaticValidation::Validator

Inherits:
Object
  • Object
show all
Defined in:
lib/graphql/static_validation/validator.rb

Overview

Initialized with a GraphQL::Schema, then it can validate Language::Nodes::Documentss based on that schema.

By default, it’s used by Query

Examples:

Validate a query

validator = GraphQL::StaticValidation::Validator.new(schema: MySchema)
query = GraphQL::Query.new(MySchema, query_string)
errors = validator.validate(query)[:errors]

Instance Method Summary collapse

Constructor Details

#initialize(schema:, rules: GraphQL::StaticValidation::ALL_RULES) ⇒ Validator

Returns a new instance of Validator.

Parameters:

  • schema (GraphQL::Schema)
  • rules (Array<#validate(context)>) (defaults to: GraphQL::StaticValidation::ALL_RULES)

    a list of rules to use when validating



16
17
18
19
# File 'lib/graphql/static_validation/validator.rb', line 16

def initialize(schema:, rules: GraphQL::StaticValidation::ALL_RULES)
  @schema = schema
  @rules = rules
end

Instance Method Details

#handle_timeout(query, context) ⇒ Object

Invoked when static validation times out.



77
78
79
80
81
# File 'lib/graphql/static_validation/validator.rb', line 77

def handle_timeout(query, context)
  context.errors << GraphQL::StaticValidation::ValidationTimeoutError.new(
    "Timeout on validation of query"
  )
end

#validate(query, validate: true, timeout: nil) ⇒ Array<Hash>

Validate query against the schema. Returns an array of message hashes.

Parameters:

  • query (GraphQL::Query)
  • validate (Boolean) (defaults to: true)
  • timeout (Float) (defaults to: nil)

    Number of seconds to wait before aborting validation. Any positive number may be used, including Floats to specify fractional seconds.

Returns:

  • (Array<Hash>)


26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/graphql/static_validation/validator.rb', line 26

def validate(query, validate: true, timeout: nil)
  query.trace("validate", { validate: validate, query: query }) do
    can_skip_rewrite = query.context.interpreter? && query.schema.using_ast_analysis? && query.schema.is_a?(Class)
    errors = if validate == false && can_skip_rewrite
      []
    else
      rules_to_use = validate ? @rules : []
      visitor_class = BaseVisitor.including_rules(rules_to_use, rewrite: !can_skip_rewrite)

      context = GraphQL::StaticValidation::ValidationContext.new(query, visitor_class)

      begin
        # CAUTION: Usage of the timeout module makes the assumption that validation rules are stateless Ruby code that requires no cleanup if process was interrupted. This means no blocking IO calls, native gems, locks, or `rescue` clauses that must be reached.
        # A timeout value of 0 or nil will execute the block without any timeout.
        Timeout::timeout(timeout) do
          # Attach legacy-style rules.
          # Only loop through rules if it has legacy-style rules
          unless (legacy_rules = rules_to_use - GraphQL::StaticValidation::ALL_RULES).empty?
            legacy_rules.each do |rule_class_or_module|
              if rule_class_or_module.method_defined?(:validate)
                rule_class_or_module.new.validate(context)
              end
            end
          end

          context.visitor.visit
        end
      rescue Timeout::Error
        handle_timeout(query, context)
      end

      context.errors
    end

    irep = if errors.empty? && context
      # Only return this if there are no errors and validation was actually run
      context.visitor.rewrite_document
    else
      nil
    end

    {
      errors: errors,
      irep: irep,
    }
  end
end