Skip to content

Commit f7c0aa4

Browse files
author
Robert Mosolgo
authored
Merge pull request #3447 from hschne/master
Update schema testing documentation
2 parents 173ad1b + ef736ce commit f7c0aa4

File tree

3 files changed

+84
-19
lines changed

3 files changed

+84
-19
lines changed

guides/testing/schema_structure.md

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,47 @@ You can read about this approach in ["Tracking Schema Changes with GraphQL-Ruby"
2525

2626
## Automatically check for breaking changes
2727

28-
You can use [GraphQL::SchemaComparator](https://github.com/xuorig/graphql-schema_comparator) to check for breaking changes during development or CI.
28+
You can use [GraphQL::SchemaComparator](https://github.com/xuorig/graphql-schema_comparator) to check for breaking changes during development or CI. If you maintain a dump of queries that typically run against your server, you may also utilize `GraphQL::StaticValidation` to validate these queries directly. A Rake task such as the one below can be used to identify changes that are incompatible with existing queries.
29+
30+
```ruby
31+
namespace :graphql do
32+
namespace :queries do
33+
desc 'Validates GraphQL queries against the current schema'
34+
task validate: [:environment] do
35+
queries_file = 'test/fixtures/files/queries.json'
36+
queries = Oj.load(File.read(queries_file))
37+
38+
Validate.run_validate(queries, MySchema)
39+
end
40+
41+
module Validate
42+
def self.run_validate(queries, schema)
43+
puts '⏳ Validating queries...'
44+
puts "\n"
45+
46+
results = queries.map { |query| schema.validate(query) }
47+
errors = results
48+
.select { |result| result[:errors].present? }
49+
.map { |result| result[:errors] }
50+
.flatten
51+
52+
if errors.empty?
53+
puts '✅ All queries are valid'
54+
else
55+
print_errors(errors)
56+
end
57+
end
58+
59+
def self.print_errors(errors)
60+
puts 'Detected the following errors:'
61+
puts "\n"
62+
63+
errors.each do |error|
64+
path = error.path.join(', ')
65+
puts "#{path}: #{error.message}"
66+
end
67+
end
68+
end
69+
end
70+
end
71+
```

lib/graphql/schema.rb

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -355,23 +355,6 @@ def using_ast_analysis?
355355
# For forwards-compatibility with Schema classes
356356
alias :graphql_definition :itself
357357

358-
# Validate a query string according to this schema.
359-
# @param string_or_document [String, GraphQL::Language::Nodes::Document]
360-
# @return [Array<GraphQL::StaticValidation::Error >]
361-
def validate(string_or_document, rules: nil, context: nil)
362-
doc = if string_or_document.is_a?(String)
363-
GraphQL.parse(string_or_document)
364-
else
365-
string_or_document
366-
end
367-
query = GraphQL::Query.new(self, document: doc, context: context)
368-
validator_opts = { schema: self }
369-
rules && (validator_opts[:rules] = rules)
370-
validator = GraphQL::StaticValidation::Validator.new(**validator_opts)
371-
res = validator.validate(query, timeout: validate_timeout)
372-
res[:errors]
373-
end
374-
375358
def deprecated_define(**kwargs, &block)
376359
super
377360
ensure_defined
@@ -712,6 +695,7 @@ def type_error=(new_proc)
712695
def_delegators :_schema_class, :unauthorized_object, :unauthorized_field, :inaccessible_fields
713696
def_delegators :_schema_class, :directive
714697
def_delegators :_schema_class, :error_handler
698+
def_delegators :_schema_class, :validate
715699

716700

717701
# Given this schema member, find the class-based definition object
@@ -861,7 +845,6 @@ class << self
861845
def_delegators :graphql_definition,
862846
# Execution
863847
:execution_strategy_for_operation,
864-
:validate,
865848
# Configuration
866849
:metadata, :redefine,
867850
:id_from_object_proc, :object_from_id_proc,
@@ -1293,6 +1276,23 @@ def validate_timeout(new_validate_timeout = nil)
12931276
end
12941277
end
12951278

1279+
# Validate a query string according to this schema.
1280+
# @param string_or_document [String, GraphQL::Language::Nodes::Document]
1281+
# @return [Array<GraphQL::StaticValidation::Error >]
1282+
def validate(string_or_document, rules: nil, context: nil)
1283+
doc = if string_or_document.is_a?(String)
1284+
GraphQL.parse(string_or_document)
1285+
else
1286+
string_or_document
1287+
end
1288+
query = GraphQL::Query.new(self, document: doc, context: context)
1289+
validator_opts = { schema: self }
1290+
rules && (validator_opts[:rules] = rules)
1291+
validator = GraphQL::StaticValidation::Validator.new(**validator_opts)
1292+
res = validator.validate(query, timeout: validate_timeout)
1293+
res[:errors]
1294+
end
1295+
12961296
attr_writer :max_complexity
12971297

12981298
def max_complexity(max_complexity = nil)

spec/graphql/schema_spec.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,4 +358,26 @@ class Schema < GraphQL::Schema
358358
assert_equal expected_message, err.message
359359
end
360360
end
361+
362+
describe 'validate' do
363+
let(:schema) { Dummy::Schema}
364+
365+
describe 'validate' do
366+
it 'validates valid query ' do
367+
query = "query sample { root }"
368+
369+
errors = schema.validate(query)
370+
371+
assert_empty errors
372+
end
373+
374+
it 'validates invalid query ' do
375+
query = "query sample { invalid }"
376+
377+
errors = schema.validate(query)
378+
379+
assert_equal(1, errors.size)
380+
end
381+
end
382+
end
361383
end

0 commit comments

Comments
 (0)