- Schema classes pass their configuration to subclasses #2384
- Improve memory consumption of lexer and complexity validator #2389
- The
install
generator creates a BaseArgument #2379 - When a field name conflicts with a built-in method name, give a warning #2376
- When a resolver argument uses
loads:
, the argument definition will preserve the type in.loads
#2365 - When an required argument is hidden, it won't add a validation error #2393
- Fix handling of invalid UTF-8 #2372, #2377
- Empty block strings are parsed correctly #2381
- For resolvers, only authorize arguments once #2378
Analysis::AST::Visitor#argument_definition
no longer returns the previous argument definition. Instead, it returns the current argument definition and#previous_argument_definition
returns the previous one. You might have to replace calls to.argument_definition
with.previous_argument_definition
for compatibility. #2226
- Accept a
subscription_scope
configuration in Subscription classes #2297 - Add a
disable_introspection_entry_points
configuration in Schema classes #2327 - Add
Analysis::AST::Visitor#argument_definition
which returns the current argument definition,#previous_argument_definition
returns the previous one #2226 - Run CI on Ruby 2.6 #2328
- Autogenerate base field class #2216
- Add timeout support with interpreter #2220
- Fix Stack overflow when calling
.to_json
on input objects #2343 - Fix off-by-one error with hasNextPage and ArrayConnections #2349
- Fix GraphQL-Pro operation store compatibility #2350
- Fix class-based transformer when multiple mutations are in one file #2309
- Use
default_graphql_name
for Edge classes #2224 - Support nested
loads:
with input objects #2323 - Support
max_complexity
with multiplex & AST analysis #2306
- Backport
String#-@
for Ruby 2.2 support #2305
- Support
rescue_from
returningGraphQL::ExecutionError
#2140 - Accept
context:
inSchema.validate
#2256 - Include
query:
in interpreter tracing forexecute_field
andexecute_field_lazy
#2236 - Add
Types::JSON
#2227 - Add
null:
option toBaseEdge.node_type
#2249
- Fix Ruby 2.2 compatibility #2302
- Distinguish aliased selections in lookahead #2266
- Properly show list enum default values in introspection #2263
- Performance improvements: #2289, #2244, #2258, #2257, #2240
- Don't recursively unwrap inputs for RelayClassicMutation #2236
- Fix
Schema::Field#scoped?
when no return type #2255 - Properly forward more authorization errors #2165
- Raise
ParseError
for.parse(nil)
#2238
GraphQL::Schema::Resolver::LoadApplicationObjectFailedError
was renamed toGraphQL::LoadApplicationObjectFailedError
. (This will only break if you're referencing the class by name and running Ruby 2.5+) #2080
- Add
Types::BigInt
#2150 - Add auto-loading arguments support in Input Object types #2080
- Add analytics tag to Datadog tracing #2154
- Fix
Query#execute
when no explicit query string is passed in #2142 - Fix when a root type returns nil because unauthorized #2144
- Fix tracing
node
by threadingowner:
through field tracing #2156 - Fix interpreter handling of exceptions raised during argument preparation #2198
- Fix ActionCableLink when there are errors but no data #2176
- Provide empty hash as default option for field resolvers #2189
- Prevent argument names from overwriting Arguments methods #2171
- Include array indices in error paths #2162
- Handle non-node arrays in AST visitor #2161
- Fix
Schema::Subscription
when it has no arguments #2135 - Don't try to scope
nil
, just skip scoping altogether #2134 - Fix when a root
.authorized?
returnsfalse
and there's noroot_value
#2136 - Fix platform tracing with interpreter & introspection #2137
- Support root Subscription types with name other than
Subscription
#2102 - Fix nested list-type input object nullability validation #2123
- Properly support connection fields with resolve procs #2115
- Properly pass errors to Resolver
load_application_object_failed
methods #2110
-
AST nodes are immutable. To modify a parsed GraphQL query, see
GraphQL::Language::Visitor
for its mutation API, which builds a new AST with the specified mutations applied. #1338, #1740 -
Cursors use urlsafe Base64. This won't break your clients (it's backwards-compatible), but it might break your tests, so it's listed here. #1698
-
Add
field(..., resolver_method:)
for when GraphQL-Ruby should call a method other than the one whose name matches the field name (#1961). This means that if you're usingmethod:
to call a different method on the Schema::Object subclass, you should update that configuration toresolver_method:
. (method:
is still used to call a different method on the underlying application object.) -
Int
type now applies boundaries as described in the spec #2101. To preserve the previous, unbounded behavior, handle the error in your schema's.type_error(err, ctx)
hook, for example:class MySchema < GraphQL::Schema def self.type_error(err, ctx) if err.is_a?(GraphQL::IntegerEncodingError) # Preserve the previous unbounded behavior # by returning the out-of-bounds value err.integer_value else super end end end
-
field(...)
configurations don't create implicit method definitions (#1961). If one resolver method depended on the implicitly-created method from another field, you'll have to refactor that call or manually add adef ...
for that field. -
Calling
super
in a field method doesn't work anymore (#1961) -
Error
"problems"
are now in"extensions" : { "problems": ... }
#2077 -
Change schema default to
error_bubbling false
#2069
- Add class-based subscriptions with
GraphQL::Schema::Subscription
#1930 - Add
GraphQL::Execution::Interpreter
(#1394) andGraphQL::Analysis::AST
(#1824) which together cut GraphQL overhead by half (time and memory) - Add
Schema.unauthorized_field(err)
for whenField#authorized?
checks fail (#1994) - Add class-based custom directives for the interpreter (#2055)
- Add
Schema::FieldExtension
for customizing field execution with class-based fields #1795 - Add
Query#lookahead
for root-level selection info #1931 - Validation errors have
"extensions": { ... }
which includes metadata about that error #1970
- Fix list-type arguments passed with a single value #2085
- Support
false
as an Enum value #2050 - Support
hash_key:
fields when the key isn't a valid Ruby method name #2016
- Fix unwrapping inputobject types when turning arguments to hashes #2094
- Support lazy objects from
.resolve_type
hooks #2108
- Fix single-item list inputs that aren't passed as lists #2095
- Fix regression in block string parsing #2032
- When an input object's argument has a validation error, that error is reported on the argument instead of its parent input object. #2013
- Add
error_bubbling false
Schema configuration for nicer validation of compound inputs #2013 - Print descriptions as block strings in SDL #2011
- Improve string-to-constant resolution #1810
- Add
Query::Context#to_hash
for splatting #1955 - Add
#dig
toSchema::InputObject
andQuery::Arguments
#1968 - Add
.*_execution_strategy
methods to class-based schemas #1914 - Accept multiple errors when adding
.rescue_from
handlers #1991
- Fix scalar tracing in NewRelic and Skylight #1954
- Fix lexer for multiple block strings #1937
- Add
unscope(:order)
when counting relations #1911 - Improve build-from-definition error message #1998
- Fix regression in legacy compat #2000
extras: [:lookahead]
injects aGraphQL::Execution::Lookahead
- Fix type printing in Printer #1902
- Rescue
GraphQL::ExecutionError
in.before_query
hooks #1898 - Properly load default values that are lists of input objects from the IDL #1874
- When using
loads:
with a nullable mutation input field, allownull
values to be provided. #1851 - When an invalid Base64 encoded cursor is provided, raise a
GraphQL::ExecutionError
instead ofArgumentError
. #1855 - Fix an issue with
extras: [:path]
would use the field'spath
instead of thecontext
. #1859
- Add scalar type generator
rails g graphql:scalar
#1847 - Add
#dig
method toQuery::Context
#1861
- When
field ...
is called with a block and the block has one argument, the field is yielded, butself
inside the block is not changed to the field. #1843
extras: [...]
can inject values from the field instance #1808- Add
ISO8601DateTime.time_precision
for customization #1845 - Fix input objects with default values of enum #1827
Schema.sync_lazy(value)
hook for intercepting lazy-resolved objects #1784
- When a field block is provided with an arity of
1
, yield the field #1843
- When using
RelayClassicMutation
,client_mutation_id
will no longer be passed toauthorized?
method #1771 - Fix issue in schema upgrader script which would cause
.to_non_null_type
calls in type definition to be ignored #1783 - Ensure enum values respond to
graphql_name
#1792 - Fix infinite resolution bug that could occur when an exception not inheriting from
StandardError
is thrown #1804
- Add
#path
method to schema members #1766 - Add
as:
argument to allow overriding the name of the argument when usingloads:
#1773 - Add support for list of IDs when using
loads:
in an argument definition #1797
-
Some mutation authorization hooks added in 1.8.5 were changed, see #1736 and #1737. Roughly:
before_prepare
was changed to#ready?
validate_*
hooks were replaced with a single#authorized?
method
- Argument default values include nested default values #1728
- Clean up duplciate method defs #1739
- Built-in support for Mongoid 5, 6, 7 #1754
- Mutation
#ready?
and#authorized?
may halt flow and/or return data #1736, #1737 - Add
.scope_items(items, ctx)
hook for filtering lists - Add
#default_graphql_name
for overriding default logic #1729 - Add
#add_argument
for building schemas #1732 - Cursors are decoded using
urlsafe_decode64
to future-proof for urlsafe cursors #1748
- Only allow Objects to implement actual Interfaces #1715. Use
include
instead for plain Ruby modules. - Revert extending interface methods onto Objects #1716. If you were taking advantage of this feature, you can create a plain Ruby module with the functionality and include it in both the interface and object.
- Support string descriptions (from June 2018 GraphQL spec) #1725
- Add some accessors to Schema members #1722
- Yield argument for definition block with arity of one #1714
- Yield field for definition blocks with arity of one #1712
- Support grouping by "endpoint" with skylight instrumentation #1663
- Validation: Don't traverse irep if no handlers are registered #1696
- Add
nodes_field
option toedge_type
to hide nodes field #1693 - Add
GraphQL::Types::ISO8601DateTime
to documentation #1694 - Conditional Analyzers #1690
- Improve error messages in
ActionCableSubscriptions
#1675 - Add Prometheus tracing #1672
- Add
map
toInputObject
#1669
- Improve the mutation generator #1718
- Fix method inheritance for interfaces #1709
- Fix Interface inheritance chain #1686
- Fix require in
tracing.rb
#1685 - Remove delegate for
FieldResolutionContext#schema
#1682 - Remove duplicated
object_class
method #1667
- GraphQL validation errors now include
"filename"
if the parsed document had afilename
#1618
TypeKind#resolves?
is deprecated in favor ofTypeKind#abstract?
#1619
- Add Mutation loading/authorization system #1609
- Interface
definition_methods
are inherited by object type classes #1635 - include
"filename"
in GraphQL errors if the parsed document has a filename #1618 - Add
Schema::InputObject#empty?
#1651 - require
ISO8601DateTime
by default #1660 - Support
extend
in the parser #1620 - Improve generator to have nicer error handling in development
- Fix
@skip
/@include
with default value offalse
#1617 - Fix lists of abstract types with promises #1613
- Don't check the type of
nil
when it's in a list #1610 - Fix NoMethodError when
variables: nil
is passed toexecute(...)
#1661 - Objects returned from
Schema.unauthorized_objects
are properly wrapped by their type proxies #1662
- Add class-based definitions for Relay types #1568
- Add a built-in auth system #1494
- Properly rescue coercion errors in variable values #1602
- Add an ISO 8601 DateTime scalar:
Types::ISO8601DateTime
. #1566 - Use classes under the hood for built-in scalars. These are now accessible via
Types::
namespace. #1565 - Add
possible_types
helpers to abstract types #1580
- Fix
Language::Visitor
when visitingInputObjectTypeDefinition
nodes to include childDirective
nodes. #1584 - Fix an issue preventing proper subclassing of
TimeoutMiddleware
. #1579 - Fix
graphql:interface
generator such that it generates working code. #1577 - Update the description of auto-generated
before
andafter
arguments to better describe their input type. #1572 - Add
Language::Nodes::DirectiveLocation
AST node to represent directive locations in directive definitions. #1564
Schema::InputObject#to_h
recursively transforms hashes to underscorized, symbolized keys. #1555
- Generators create class-based types #1562
Schema::InputObject#to_h
returns a underscorized, symbolized hash #1555
- Support
default_mask
in class-based schemas #1563 - Fix null propagation for list types #1558
- Validate unique arguments in queries #1557
- Fix
RelayClassicMutation
s with no arguments #1543
- When filtering items out of a schema, Unions will now be hidden if their possible types are all hidden or if all fields returning it are hidden. #1515
GraphQL::ExecutionError.new
accepts anextensions:
option which will be merged into the"extensions"
key in that error's JSON #1552
- When filtering items out of a schema, Unions will now be hidden if their possible types are all hidden or if all fields returning it are hidden. #1515
- Require that fields returning interfaces have selections made on them #1551
- Correctly mark introspection types and fields as
introspection?
#1535 - Remove unused introspection objects #1534
- use
object
/context
in the upgrader instead of@object
/@context
#1529 - (Development) Don't require mongodb for non-mongo tests #1548
- Track position of union member nodes in the parser #1541
1.8.0
has been in prerelease for 6 months. See the prerelease changelog for change-by-change details. Here's a high-level changelog, followed by a detailed list of changes since the last prerelease.
- GraphQL-Ruby is not tested on Ruby 2.1. #1070 Because Ruby 2.1 doesn't garbage collect Symbols, it's possible that GraphQL-Ruby will introduce a OOM vulnerability where unique symbols are dynamically created, for example, turning user input into Symbols. No instances of this are known in GraphQL-Ruby ... yet!
GraphQL::Delegate
, a duplicate of Ruby'sForwardable
, was removed. UseForwardable
instead, and update your Ruby if you're on2.4.0
, due to a performance regression inForwardable
in that version.MySchema.subscriptions.trigger
asserts that its inputs are valid arguments #1400. So if you were previously passing invalid options there, you'll get an error. Remove those options.
- A new class-based API for schema definition. The old API is completely supported, but the new one is much nicer to use. If you migrate, some schema extensions may require a bit of extra work.
- Built-in support for Mongoid-backed Relay connections
.execute(variables: ...)
andsubscriptions.trigger
both accept Symbol-keyed hashes- Lots of other small things around SDL parsing, tracing, runtime ... everything. Read the details below for a full list.
- Many, many bug fixes. See the detailed list if you're curious about specific bugs.
GraphQL::Schema::Field#initialize
's signature changed to accept keywords and a block only.type:
,description:
andname:
were moved to keywords. SeeField.from_options
for how thefield(...)
helper's arguments are merged to go toField.new
. #1508
Schema::Resolver
is a replacement forGraphQL::Function
#1472- Fix subscriptions with class-based schema #1478
Tracing::NewRelicTracing
acceptsset_transaction_name:
to use the GraphQL operation name as the NewRelic transaction name #1430
- Backported
accepts_definition
s are inherited #1514 - Fix Schema generator's
resolve_type
method #1481 - Fix constant assignment warnings with interfaces including multiple other interfaces #1465
- InputObject types loaded from SDL have the proper AST node assigned to them #1512
-
Schema::Mutation.resolve_mutation
was moved to an instance method; see changes toSchema::RelayClassicMutation
in #1469 for an example refactor -
GraphQL::Delegate
was removed, use Ruby'sForwardable
instead (warning: bad performance on Ruby 2.4.0) -
GraphQL::Schema::Interface
is a module, not a class #1372. To refactor, use a base module instead of a base class:module BaseInterface include GraphQL::Schema::Interface end
And include that in your interface types:
module Reservable include BaseInterface field :reservations, ... end
In object types, no change is required; use
implements
as before:class EventVenue < BaseObject implements Reservable end
GraphQL::Schema::Interface
is a module- Support
prepare:
andas:
argument options #1469 - First-class support for Mongoid connections #1452
- More type inspection helpers for class-based types #1446
- Field methods may call
super
to get the default behavior #1437 variables:
accepts symbol keys #1401- Reprint any directives which were parsed from SDL #1417
- Support custom JSON scalars #1398
- Subscription
trigger
accepts symbol, underscored arguments and validates their presence #1400 - Mutations accept a
null(true | false)
setting to affect field nullability #1406 RescueMiddleware
uses inheritance to match errors #1393- Resolvers may return a list of errors #1231
- Better error for anonymous class names #1459
- Input Objects correctly inherit arguments #1432
- Fix
.subscriptions
for class-based Schemas #1391
- Add
Schema::Mutation
andSchema::RelayClassicMutation
base classes #1360
- Fix using anonymous classes for field types #1358
- New version number. (I needed this because I messed up build tooling for 1.8.0.pre8).
- Backport
accepts_definition
for configurations #1357 - Add
#owner
method to Schema objects - Add
Interface.orphan_types
config for orphan types #1346 - Add
extras: :execution_errors
foradd_error
#1313 - Accept a block to
Schema::Argument#initialize
#1356
- Support
cursor_encoder
#1357 - Don't double-count lazy/eager field time in Tracing #1321
- Fix camelization to support single leading underscore #1315
- Fix
.resolve_type
for Union and Interface classes #1342 - Apply kwargs before block in
Argument.from_dsl
#1350
- Upgrader improvements #1305
- Support
global_id_field
for interfaces #1299 - Add
camelize: false
#1300 - Add readers for
context
,object
andarguments
#1283 - Replace
Schema.method_missing
with explicit whitelist #1265
- Custom enum value classes #1264
- Properly print SDL type directives #1255
- Upgrade argument access with the upgrader #1251
- Add
Schema#find(str)
for finding schema members by name #1232
- Fix
Schema.max_complexity
#1246 - Support cyclical connections/edges #1253
Type.fields
,Field.arguments
,Enum.values
andInputObject.arguments
return a Hash instead of an Array #1222
- By default, fields try hash keys which match their name, as either a symbol or a string #1225
field do ... end
instance_evals on the Field instance, not a FieldProxy #1227[T, null: true]
creates lists with nullable items #1229- Upgrader improvements #1223
- Don't require
parser
unless the upgrader is run #1218
- Custom
Context
classes for class-based schemas #1161 - Custom introspection for class-based schemas #1170
- Improvements to upgrader tasks and internals #1151, #1178, #1212
- Allow description inside field blocks #1175
- Add
rake graphql:upgrade[app/graphql]
for automatic upgrade #1110 - Automatically camelize field names and argument names #1143, #1126
- Improved error message when defining
name
instead ofgraphql_name
#1104
- Fix list wrapping when value is
nil
#1117 - Fix ArgumentError typo #1098
- Stop official support for Ruby 2.1 #1070
- Add class-based schema definition API #1037
- Support new IDL spec for
&
for interfaces #1304 - Schema members built from IDL have an
#ast_node
#1367
- Fix paging backwards with
hasNextPage
#1319 - Add hint for
orphan_types
in error message #1380 - Use an empty hash for
result
when a query has unhandled errors #1382
Schema#as_json
returns a hash, not aGraphQL::Query::Result
#1288
typed_children
should always return a Hash #1278
- Fix compatibility of
irep_node.typed_children
on leaf nodes #1277
- Empty selections (
{ }
) are invalid in the GraphQL spec, but were previously allowed by graphql-ruby. They now return a parse error. #1268
- Fix error when inline fragments are spread on scalars #1268
- Fix printing SDL when types have interfaces and directives #1255
- Support block string inputs #1219
- Fix deprecation regression in schema printer #1250
- Fix resource names in DataDog tracing #1208
- Fix passing
context
to multiplex inQuery#result
#1200
- Refactor
Schema::Printer
to useLanguage::Printer
#1159 - Add
ArgumentValue#default_used?
andArguments#default_used?
#1152
- Fix Scout Tracing #1187
- Call
#inspect
forEnumType::UnresolvedValueError
#1179 - Parse empty field sets in IDL parser #1145
Schema#to_document
returns aLanguage::Nodes::Document
#1134- Add
trace_scalars
andtrace: true|false
to monitoring #1103 - Add
Tracing::DataDogPlatform
monitoring #1129 - Support namespaces in
rails g graphql:function
and:loader
#1127 - Support
serializer:
option forActionCableSubscriptions
#1085
- Properly count the column after a closing quote #1136
- Fix default value input objects in
Schema.from_definition
#1135 - Fix
rails destroy graphql:mutation
#1119 - Avoid unneeded query in RelationConnection with Sequel #1101
- Improve & document instrumentation stack behavior #1101
- Serialize symbols in with
GraphQL::Subscriptions::Serialize
#1084
- Rename
Backtrace::InspectResult#inspect
to#inspect_result
#1022
- Improved website search with Algolia #934
- Support customized generator directory #1047
- Recursively serialize
GlobalID
-compliant objects in Arrays and hashes #1030 - Add
Subscriptions#build_id
helper #1046 - Add
#non_null?
and#list?
helper methods to type objects #1054
- Fix infinite loop in query instrumentation when error is raised #1074
- Don't try to trace error when it's not raised during execution
- Improve validation of query variable definitions #1073
- Fix Scout tracing module load order #1064
GraphQL::Tracing.install
is deprecated, use schema-local or query-local tracers instead #996
- Add monitoring plugins for AppSignal, New Relic, Scout and Skylight #994, #1013
- Custom coercion errors for custom scalars #988
- Extra
options
forGraphQL::ExecutionError
#1002 - Use
GlobalID
for subscription serialization when available #1004 - Schema- and query-local, threadsafe tracers #996
- Accept symbol-keyed arguments to
.trigger
#1009
- Fix arguments on
Query.__type
field #978 - Fix
Relay::Edge
objects inBacktrace
tables #975
- Correctly skip connections that return
ctx.skip
#972
- Properly release changes from 1.7.0
GraphQL::Result
is the returned from GraphQL execution. #898Schema#execute
andQuery#result
both return aGraphQL::Result
. It implements Hash-like methods to preserve compatibility.
-
puts ctx.backtrace
prints out a GraphQL backtrace table #946 -
GraphQL::Backtrace.enable
wraps unhandled errors with GraphQL backtraces #946 -
GraphQL::Relay::ConnectionType.bidrectional_pagination = true
turns on true bi-directional pagination checks forhasNextPage
/hasPreviousPage
fields. This will become the default behavior in a future version. #960 -
Field arguments may be accessed as methods on the
args
object. This is an alternative to#[]
syntax which provides did-you-mean behavior instead of returningnil
on a typo. #924 For example:# using hash syntax: args[:limit] # => 10 args[:limittt] # => nil # using method syntax: args.limit # => 10 args.limittt # => NoMethodError
The old syntax is not deprecated.
-
Improvements to schema filters #919
- If a type is not referenced by anything, it's hidden
- If a type is an abstract type, but has no visible members, it's hidden
-
GraphQL::Argument.define
builds re-usable arguments #948 -
GraphQL::Subscriptions
provides hooks for subscription platforms #672 -
GraphQL::Subscriptions::ActionCableSubscriptions
implements subscriptions over ActionCable #672 -
More runtime values are accessble from a
ctx
object #923 :ctx.parent
returns thectx
from the parent fieldctx.object
returns the currentobj
for that fieldctx.value
returns the resolved GraphQL value for that field
These can be used together, for example,
ctx.parent.object
to get the parent object. -
GraphQL::Tracing
provides more hooks into gem internals for performance monitoring #917 -
GraphQL::Result
provides access to the originalquery
andcontext
after executing a query #898
- Prevent passing both query string and parsed document to
Schema#execute
#957 - Prevent invalid names for types #947
- Validate against EnumType value names to match
/^[_a-zA-Z][_a-zA-Z0-9]*$/
#915
- Use stdlib
forwardable
when it's not Ruby 2.4.0 #926 - Improve
UnresolvedTypeError
message #928 - Add a default field to the Rails generated mutation type #922
- Find types via directive arguments when traversing the schema #944
- Assign
#connection?
when building a schema from IDL #941 - Initialize
@edge_class
tonil
#942 - Disallow invalid enum values #915
- Disallow doubly-nested non-null types #916
- Fix
Query#selected_operation_name
when no selections are present #899 - Fix needless
COUNT
query forhasNextPage
#906 - Fix negative offset with
last
argument #907 - Fix line/col for
ArgumentsAreDefined
validation #890 - Fix Sequel error when limit is
0
#892
- Add
GraphQL.parse_file
andAbstractNode#filename
#873 - Support
.graphql
filepaths withSchema.from_definition
#872
- Fix variable usage inside non-null list #888
- Fix unqualified usage of ActiveRecord::Relation #885
- Fix
FieldsWillMerge
handling of equivalent input objects - Fix to call
prepare:
on nested input types
- Validate
graphql-pro
downloads withrake graphql:pro:validate[$VERSION]
#846
- Remove usage of Rails-only
Array.wrap
#840 - Fix
RelationConnection
to count properly when relation contains an alias #838 - Print name of Enum type when a duplicate value is added #843
-
Schema#types[](type_name)
returnsnil
when there's no type namedtype_name
(it used to raiseRuntimeError
). To get an error for missing types, use.fetch
instead, for example:# Old way: MySchema.types[type_name] # => may raise RuntimeError # New way: MySchema.types.fetch(type_name) # => may raise KeyError
-
Schema build steps happen in one pass instead of two passes #819 . This means that
instrument(:field)
hooks may not accessSchema#types
,Schema#possible_types
orSchema#get_field
, since the underlying data hasn't been prepared yet. There's not really a clear upgrade path here. It's a bit of a mess. If you're affected by this, feel free to open an issue and we'll try to find something that works!
-
Schema#resolve_type
is now called with(abstract_type, obj, ctx)
instead of(obj, ctx)
#834 . To update, add an unused parameter to the beginning of yourresolve_type
hook:MySchema = GraphQL::Schema.define do # Old way: resolve_type ->(obj, ctx) { ... } # New way: resolve_type ->(type, obj, ctx) { ... } end
rails g graphql:mutation
will add Mutation boilerplate if it wasn't added already #812InterfaceType
andUnionType
both acceptresolve_type ->(obj, ctx) { ... }
functions for type-specific resolution. This function takes precedence overSchema#resolve_type
#829 #834Schema#resolve_type
is called with three arguments,(abstract_type, obj, ctx)
, so you can distinguish object type based on interface or union.Query#operation_name=
may be assigned during query instrumentation #833query.context.add_error(err)
may be used to add query-level errors #833
argument(...)
DSL accepts custom keywords #809- Use single-query
max_complexity
overrides #812 - Return a client error when
InputObjectType
receives an array as input #803 - Properly handle raised errors in
prepare
functions #805 - Fix using
as
andprepare
inargument do ... end
blocks #817 - When types are added to the schema with
instrument(:field, ...)
, make sure they're inSchema#types
#819 - Raise an error when duplicate
EnumValue
is created #831 - Properly resolve all query levels breadth-first when using
lazy_resolve
#835 - Fix tests to run on PostgresQL; Run CI on PostgresQL #814
- When no query string is present, return a client error instead of raising
ArgumentError
#833 - Properly validate lists containing variables #824
Schema.to_definition
sorts fields and arguments alphabetically #775validate: false
skips static validations in query execution #790
graphql:install
addsoperation_name: params[:operationName]
#786graphql:install
skipsgraphiql-rails
for API-only apps #772SerialExecution
calls.is_a?(Skip)
to avoid user-defined#==
methods #794prepare:
functions which returnExecutionError
are properly handled when default values are present #801
- Run multiplex instrumentation when running a single query with a legacy execution strategy #766
- Check each strategy when looking for overridden execution strategy #765
- Correctly wrap
Method
s with BackwardsCompatibility #763 - Various performance improvements #764
- Don't call
#==(other)
on user-provided objects (use.is_a?
instead) #761 - Support lazy object from custom connection
#edge_nodes
#762 - If a lazy field returns an invalid null, stop evaluating its siblings #767
Schema.define { default_max_page_size(...) }
provides a Connectionmax_page_size
when no other is provided #752Schema#get_field(type, field)
accepts a string type name #756Schema.define { rescue_from(...) }
accepts multiple error classes for the handler #758
- Use
*_execution_strategy
when executing a single query (doesn't supportSchema#multiplex
) #755 - Fix NameError when
ActiveRecord
isn't loaded #747 - Fix
Query#mutation?
etc to support lazily-loaded AST #754
Query#selected_operation_name
returns the operation to execute, even if it was inferred (not provided asoperation_name:
) #746
- Return
nil
fromQuery#operation_name
if nooperation_name:
was provided #746
-
InternalRepresentation::Node#return_type
will now return the wrapping type. Usereturn_type.unwrap
to access the old value #704 -
instrument(:query, ...)
instrumenters are applied as a stack instead of a queue #735. If you depend on queue-based behavior, move yourbefore_query
andafter_query
hooks to separate instrumenters. -
In a
Relay::Mutation
, Raising or returning aGraphQL::Execution
will nullify the mutation field, not the field's children. #731 -
args.to_h
returns a slightly different hash #714- keys are always
String
s - if an argument is aliased with
as:
, the alias is used as the key
- keys are always
-
InternalRepresentation::Node#return_type
includes the original "wrapper" types (non-null or list types), call.unwrap
to get the inner type #20# before irep_node.return_type # after irep_node.return_type.unwrap
-
Argument
prepare
functions which take one argument are deprecated #730# before argument :id, !types.ID, prepare: ->(val) { ... } # after argument :id, !types.ID, prepare: ->(val, ctx) { ... }
Schema#multiplex(queries)
runs multiple queries concurrently #691GraphQL::RakeTask
supports dumping the schema to IDL or JSON #687- Improved support for
Schema.from_definition
#699 :- Custom scalars are supported with
coerce_input
andcoerce_result
functions resolve_type
function will be used for abstract types- Default resolve behavior is to check
obj
for a method and call it with 0, 1, or 2 arguments.
- Custom scalars are supported with
ctx.skip
may be returned from field resolve functions to exclude the field from the response entirely #688instrument(:field, ..., after_built_ins: true)
to apply field instrumentation after Relay wrappers #740- Argument
prepare
functions are invoked with(val, ctx)
(previously, it was only(val)
) #730 args.to_h
returns stringified, aliased arguments #714ctx.namespace(:my_namespace)
provides namespaced key-value storage #689GraphQL::Query
can be initialized without a query_string; it can be added after initialization #710- Improved filter support #713
Schema.execute(only:, except:)
accept a callable or an array of callables (multiple filters)- Filters can be added to a query via
Query#merge_filters(only:, except:)
. You can add a filter to every query by merging it in during query instrumentation.
- Correctly apply cursors and
max_page_size
inRelay::RelationConnection
andRelay::ArrayConnection
#728 - Nullify a mutation field when it raises or returns an error #731
UniqueWithinType
Relay ID generator supports-
in the ID #742assign_metadata_key
assignstrue
when the definition method is called without arguments #724- Improved lexer performance #737
- Assign proper
parent
when aconnection
resolve returns a promise #736
- Fix raising
ExecutionError
inside mutation resolve functions (it nullifies the field) #722
- Fix returning
nil
from connection resolve functions (now they becomenull
) #719 - Fix duplicate AST nodes when merging fragments #721
Schema.from_definition
accepts aparser:
option (to work around lack of schema parser ingraphql-libgraphqlparser
) #712Query#internal_representation
exposes anInternalRepresentation::Document
#701- Update generator usage of
graphql-batch
#697
- Handle fragments with the same name as operations #706
- Fix type generator: ensure type name is camelized #718
- Fix
Query#operation_name
to return the operation name #707 - Fix pretty-print of non-null & list types #705
- Fix single input objects passed to list-type arguments #716
- Support Rails 5.1 #693
- Fall back to
String#encode
for non-UTF-8/non-ASCII strings #676
- Correctly apply
Relay::Mutation
'sreturn_field ... property:
argument #692 - Handle Rails 5.1's
ActionController::Parameters
#693
- Include instrumentation-related changes in introspection result #681
- Use Relay PageInfo descriptions from graphql-js #673
- Allow fields with different arguments when fragments are included within inline fragments of non-overlapping types #680
- Run
lazy_resolve
instrumentation forconnection
fields #679
InternalRepresentation::Node#definition
returnsnil
instead of raising NoMethodError for operation fields #675Field#function
is properly populated for fields derived fromGraphQL::Function
s #674
-
Returned strings which aren't encoded as UTF-8 or ASCII will raise
GraphQL::StringEncodingError
instead of becomingnil
#661To preserve the previous behavior, Implement
Schema#type_error
to returnnil
for this error, eg:GraphQL::Schema.define do type_error ->(err, ctx) { case err # ... when GraphQL::StringEncodingError nil end }
-
coerce_non_null_input
andvalidate_non_null_input
are private #667
-
One-argument
coerce_input
andcoerce_result
functions for custom scalars are deprecated. #667 Those functions now accept a second argument,ctx
.# From ->(val) { val.to_i } # To: ->(val, ctx) { val.to_i }
-
Calling
coerce_result
,coerce_input
,valid_input?
orvalidate_input
without actx
is deprecated. #667 Usecoerce_isolated_result
coerce_isolated_input
,valid_isolated_input?
,validate_input
to explicitly bypassctx
.
- Include
#types
inGraphQL::Function
#654 - Accept
prepare:
function for arguments #646 - Scalar coerce functions receive
ctx
#667
- Properly apply default values of
false
#658 - Fix application of argument options in
GraphQL::Relay::Mutation
#660 - Support concurrent-ruby
>1.0.0
#663 - Only raise schema validation errors on
#execute
to avoid messing with Rails constant loading #665
- Improve threadsafety of
lazy_resolve
cache, useConcurrent::Map
if it's available #631 - Properly handle unexpeced input objects #638
- Handle errors during definition by preseriving the definition #632
- Fix
nil
input for nullable list types #637, #639 - Handle invalid schema IDL with a validation error #647
- Properly serialize input object default values #635
- Fix
as:
on mutationinput_field
#650 - Fix null propagation for
nil
members of non-null list types #649
- Stop supporting deprecated one-argument schema masks #616
- Return a client error for unknown variable types when default value is provided or when directives are present #627
- Fix validation performance regression on nested abstract fragment conditions #622, #624
- Put back
InternalRepresentation::Node#parent
and fix it for fragment fields #621 - Ensure enum names are strings #619
-
Fix infinite loop triggered by user input. #620 This query would cause an infinite loop:
query { ...frag } fragment frag on Query { __typename } fragment frag on Query { ...frag }
-
Validate fragment name uniqueness #618
-
Parse errors are no longer raised to the application. #607 Instead, they're returned to the client in the
"errors"
key. To preserve the previous behavior, you can implementSchema#parse_error
to raise the error:MySchema = GraphQL::Schema.define do # ... parse_error ->(err, ctx) { raise(err) } end
- Add
graphq:enum
generator #611 - Parse errors are returned to the client instead of raised #607
- Handle negative cursor pagination args as
0
#612 - Properly handle returned
GraphQL::ExecutionError
s from connection resolves #610 - Properly handle invalid nulls in lazy scalar fields #609
- Properly handle invalid input objects passed to enum arguments #604
- Fix introspection response of enum default values #605
- Allow
Schema.from_definition
default resolver hashes to have defaults #608
- Fix rewrite performance regressions from 1.5.0 #599
- Remove unused
GraphQL::Execution::Lazy
initialization API #597
-
Only UTF-8-encoded strings will be returned by
String
fields. Strings with other encodings (or objects whose#to_s
method returns a string with a different encoding) will returnnil
instead of that string. #517To opt into the previous behavior, you can modify
GraphQL::STRING_TYPE
:# app/graphql/my_schema.rb # Restore previous string behavior: GraphQL::STRING_TYPE.coerce_result = ->(value) { value.to_s } MySchema = GraphQL::Schema.define { ... }
-
Substantial changes to the internal query representation (#512, #536). Query analyzers may notice some changes:
- Nodes skipped by directives are not visited
- Nodes are always on object types, so
Node#owner_type
always returns an object type. (Interfaces and Unions are replaced with concrete object types which are valid in the current scope.)
See changes to
Analysis::QueryComplexity
for an example migration. Here are some other specific changes:- Nodes are tracked on object types only, not interface or union types
- Deprecated, buggy
Node#children
andNode#path
were removed - Buggy
#included
was removed - Nodes excluded by directives are entirely absent from the rewritten tree
- Internal
InternalRepresentation::Selection
was removed (no longer needed) Node#spreads
was replaced byNode#ast_spreads
which returns a Set
Schema#validate
returns a list of errors for a query string #513implements ...
adds interfaces to object types without inherit-by-default #548, #574GraphQL::Relay::RangeAdd
for implementingRANGE_ADD
mutations #587use ...
definition method for plugins #565- Rails generators #521, #580
GraphQL::Function
for reusable resolve behavior with arguments & return type #545- Support for Ruby 2.4 #475
- Relay
node
&nodes
field can be extended with a custom block #552 - Performance improvements:
- Resolve fragments only once when validating #504
- Reuse
Arguments
objects #500 - Skip needless
FieldResult
s #482 - Remove overhead from
ensure_defined
#483 - Benchmark & Profile tasks for gem maintenance #520, #579
- Fetch
has_next_page
while fetching items inRelationConnection
#556 - Merge selections on concrete object types ahead of time #512
- Support runnable schemas with
Schema.from_definition
#567, #584
- Support different arguments on non-overlapping typed fragments #512
- Don't include children of
@skip
ped nodes when parallel branches are not skipped #536 - Fix offset in ArrayConnection when it's larger than the array #571
- Add missing
frozen_string_literal
comments #589
- When an operation name is provided but no such operation is present, return an error (instead of executing the first operation) #563
- Require unique operation names #563
- Require selections on root type #563
- If a non-null field returns
null
, don't resolve any more sibling fields. #575
Relay::Node.field
andRelay::Node.plural_field
accept a customresolve:
argument #550Relay::BaseConnection#context
provides access to the query context #537- Allow re-assigning
Field#name
#541 - Support
return_interfaces
onRelay::Mutation
s #533 BaseType#to_definition
stringifies the type to IDL #539argument ... as:
can be used to alias an argument inside the resolve function #542
- Fix negative offset from cursors on PostgresQL #510
- Fix circular dependency issue on
.connection_type
s #535 - Better error when
Relay::Mutation.resolve
doesn't return a Hash
GraphQL::Relay::Node.plural_field
finds multiple nodes by UUID #525
- Properly handle errors from lazy mutation results #528
- Encode all parsed strings as UTF-8 #516
- Improve error messages #501 #519
- Absent variables aren't present in
args
(again!) #494 - Ensure definitions were executed when accessing
Field#resolve_proc
#502 (This could have caused errors when multiple instrumenters modified the same field in the schema.)
- Absent variables aren't present in
args
#479 - Fix grouped ActiveRecord relation with
last
only #476 Schema#default_mask
& queryonly:
/except:
are combined, not overriden #485- Root types can be hidden with dynamic filters #480
-
One-argument schema filters are deprecated. Schema filters are now called with two arguments,
(member, ctx)
. #463 To update, add a second argument to your schema filter. -
The arity of middleware
#call
methods has changed. Instead ofnext_middleware
being the last argument, it is passed as a block. To update, callyield
to continue the middleware chain or use&next_middleware
to capturenext_middleware
into a local variable.# Previous: def call(*args, next_middleware) next_middleware.call end # Current def call(*args) yield end # Or def call(*args, &next_middleware) next_middleware.call end
-
You can add a
nodes
field directly to a connection. #451 That way you can say{ friends { nodes } }
instead of{ freinds { edges { node } } }
. Either passnodes_field: true
when defining a custom connection type, for example:FriendsConnectionType = FriendType.define_connection(nodes_field: true)
Or, set
GraphQL::Relay::ConnectionType.default_nodes_field = true
before defining your schema, for example:GraphQL::Relay::ConnectionType.default_nodes_field = true MySchema = GraphQL::Schema.define { ... }
-
Middleware performance was dramatically improved by reducing object allocations. #462
next_middleware
is now passed as a block. In general,yield
is faster than calling a captured block. -
Improve error messages for wrongly-typed variable values #423
-
Cache the value of
resolve_type
per object per query #462 -
Pass
ctx
to schema filters #463 -
Accept whitelist schema filters as
only:
#463 -
Add
Schema#to_definition
which acceptsonly:/except:
to filter the schema when printing #463 -
Add
Schema#default_mask
as a defaultexcept:
filter #463 -
Add reflection methods to types #473
#introspection?
marks built-in introspection types#default_scalar?
marks built-in scalars#default_relay?
marks built-in Relay types#default_directive?
marks built-in directives
- Fix ArrayConnection: gracefully handle out-of-bounds cursors #452
- Fix ArrayConnection & RelationConnection: properly handle
last
withoutbefore
#362
- As per the spec,
__
prefix is reserved for built-in names only. This is currently deprecated and will be invalid in a future version. #427, #450
Schema#lazy_resolve
allows you to define handlers for a second pass of resolution #386Field#lazy_resolve
can be instrumented to track lazy resolution #429Schema#type_error
allows you to handleInvalidNullError
s andUnresolvedTypeErrors
in your own way #416Schema#cursor_encoder
can be specified for transforming cursors from built-in Connection implementations #345- Schema members
#dup
correctly: they shallowly copy their state into new instances #444 Query#provided_variables
is now public #430
- Schemas created from JSON or strings with custom scalars can validate queries (although they still can't check if inputs are valid for those custom scalars) #445
- Always use
quirks_mode: true
when serializing values (to support non-stdlibJSON
s) #449 - Calling
#redefine
on a Schema member copies state outside of previous#define
blocks (uses#dup
) #444
- Preserve connection behaviors after
redefine
#421 - Implement
respond_to_missing?
onDefinedObjectProxy
(which isself
inside.define { ... }
) #414
Visitor
received some breaking changes, though these are largely-private APIs (#401):- Global visitor hooks (
Visitor#enter
andVisitor#leave
) have been removed - Returning
SKIP
from a visitor hook no longer skips sibling nodes
- Global visitor hooks (
Schema#instrument
may be called outside ofSchema.define
#399- Validation: assert that directives on a node are unique #409
instrument(:query)
hooks are executed even if the query raises an error #412
Mutation#input_fields
should trigger lazy definition #392ObjectType#connection
doesn't modify the providedGraphQL::Field
#411Mutation#resolve
may return aGraphQL::ExecutionError
#405Arguments
can handle nullable arguments passed asnil
#410
- For invalid enum values, print the enum name in the error message (not a Ruby object dump) #403
- Improve detection of invalid UTF-8 escapes #394
Lexer
previous token should be a local variable, not a method attribute #396Arguments
should wrap values according to their type, not their value #398
Schema.execute
raises an error ifvariables:
is a string
- Dynamic fields
__schema
,__type
and__typename
are properly validated #391
- Implement
Query::Context#strategy
andFieldResolutionContext#strategy
to support GraphQL::Batch #382
-
A breaking change from 1.1.0 was reverted: two-character
"\\u"
is longer treated as the Unicode escape character #372 -
Due to the execution bug described below, the internal representation of a query has changed. Although
Node
responds to the same methods, tree is built differently and query analyzers visit it differently. #373, #379The difference is in cases like this:
outer { ... on A { inner1 { inner2 } } ... on B { inner1 { inner3 } } }
Previously, visits would be:
outer
, which has one child:inner1
, which has two definitions (one onA
, another onB
), then visit its twochildren
:inner2
which has one definition (on the return type ofinner1
)inner3
which has one definition (on the return type ofinner1
)
This can be wrong for some cases. For example, if
A
andB
are mutually exclusive (both object types, or union types with no shared members), theninner2
andinner3
will never be executed together.Now, the visit goes like this:
outer
which has two entries intyped_children
, one onA
and another onB
. Visit eachtyped_chidren
branch:inner1
, then its onetyped_children
branch:inner2
inner1
, then its onetyped_children
branch:inner3
As you can see, we visit
inner1
twice, once for each type condition.inner2
andinner3
are no longer visited as siblings. Instead they're visited as ... cousins? (They share a grandparent, not a parent.)Although
Node#children
is still present, it may not contain all children actually resolved at runtime, since multipletyped_children
branches could apply to the same runtime type (eg, two branches on interface types can apply to the same object type). To track all children, you have to do some bookkeeping during visitation, seeQueryComplexity
for an example.You can see PR #373 for how built-in analyzers were changed to reflect this.
InternalRepresentation::Node#children
andInternalRepresentation::Node#definitions
are deprecated due to the bug described below and the breaking change described above. Instead, useInternalRepresentation::Node#typed_children
andInternalRepresentation::Node#defininition
. #373
-
null
support for the whole library: as a query literal, variable value, and argument default value. To check for the presence of a nullable, useArguments#key?
#369 -
GraphQL::Schema::UniqueWithinType.default_id_separator
may be assigned to a custom value #381 -
Context#add_error(err)
may be used to add aGraphQL::ExecutionError
to the response's"errors"
key (and the resolve function can still return a value) #367 -
The third argument of
resolve
is now aFieldResolutionContext
, which behaves just like aQuery::Context
, except that it is not modified during query execution. This means you can capture a reference to that context and access some field-level details after the fact:#path
,#ast_node
,#irep_node
. (Other methods are delegated to the underlyingQuery::Context
) #379 -
TimeoutMiddleware
's second argument is a proxied query object: it's#context
method returns theFieldResolutionContext
(see above) for the timed-out field. Other methods are delegated to the underlyingQuery
#379
-
Fix deep selection merging on divergently-typed fragments. #370, #373, #379 Previously, nested selections on different fragments were not distinguished. Consider a case like this:
... on A { inner1 { inner2 } } ... on B { inner1 { inner3 } }
Previously, an object of type
A
would resolveinner1
, then the result would receive bothinner2
andinner3
. The same was true for an object of typeB
.Now, those are properly distinguished. An object of type
A
resolvesinner1
, then its result receivesinner2
. An object of typeB
receivesinner1
, theninner3
.
- Two-character
"\\u"
is no longer treated as the Unicode escape character, only the Unicode escape character"\u"
is treated that way. (This behavior was a bug, the migration path is to use the Unicode escape character.) #366 GraphQL::Language::ParserTests
was removed, useGraphQL::Compatibility
instead. #366- Non-null arguments can't be defined with default values, because those values would never be used #361
Schema.from_definition(definition_string)
builds aGraphQL::Schema
out of a schema definition. #346- Schema members (types, fields, arguments, enum values) can be hidden on a per-query basis with the
except:
option #300 GraphQL::Compatibility
contains.build_suite
functions for testing user-provided parsers and execution strategies with GraphQL internals. #366- Schema members respond to
#redefine { ... }
for making shallow copies with extended definitions. #357 Schema#instrument
provides an avenue for observing query and field resolution with no overhead.- Some
SerialExecution
objects were converted to functions, resulting in a modest performance improvement for query resolution.
NonNullType
andListType
have no name (nil
), as per the spec #355- Non-null arguments can't be defined with default values, because those values would never be used #361
validate: false
option removed fromSchema.execute
(it didn't work anyways) #338- Some deprecated methods were removed: #349
BaseConnection#object
was removed, useBaseConnection#nodes
BaseConnection.connection_for_items
was removed, useBaseConnection#connection_for_nodes
- Two-argument resolve functions for
Relay::Mutation
s are not supported, use three arguments instead:(root_obj, input, ctx)
Schema.new
no longer accepts initialization options, useSchema.define
insteadGraphQL::ObjectType::UnresolvedTypeError
was removed, useGraphQL::UnresolvedTypeError
instead
- Fragment type conditions should be parsed as
TypeName
nodes, not strings. (Users ofgraphql-libgraphqlparser
should update to1.0.0
of that gem.) #342
- Set
ast_node
andirep_node
on query context before sending it to middleware #348 - Enum values can be extended with
.define
#341
- Use
RelationConnection
for Rails 3 relations (which also extendArray
) #343 - Fix schema printout when arguments have comments #335
Relay::BaseConnection#order
was removed (it always returnednil
) #313- In the IDL, Interface names & Union members are parsed as
TypeName
nodes instead of Strings #322
- Print and parse descriptions in the IDL #305
- Schema roots from IDL are omitted when their names match convention #320
- Don't add
rescue_middleware
to a schema if it's not usingrescue_from
#328 Query::Arguments#each_value
yieldsQuery::Argument::ArgumentValue
instances which contain key, value and argument definition #331
- Use
JSON.generate(val, quirks_mode: true)
for compatibility with other JSON implementations #316 - Improvements for compatibility with 1.9.3 branch #315 #314 #313
- Raise a descriptive error when calculating a
cursor
for a node which isn't present in the connection's members #327
GraphQL::Query::Arguments.new
requiresargument_definitions:
of type{String => GraphQL::Argument }
#304
-
Relay::Mutation#resolve
has a new signature. #301Previously, it was called with two arguments:
resolve ->(inputs, ctx) { ... }
Now, it's called with three inputs:
resolve ->(obj, inputs, ctx) { ... }
obj
is the value ofroot_value:
given toSchema#execute
, as with other root-level fields.Two-argument resolvers are still supported, but they are deprecated and will be removed in a future version.
Relay::Mutation
accepts a user-definedreturn_type
#310Relay::Mutation#resolve
receives theroot_value
passed toSchema#execute
#301- Derived
Relay
objects have descriptions #303
- Introspection query is 7 levels deep instead of 3 #308
- Unknown variable types cause validation errors, not runtime errors #310
Query::Arguments
doesn't wrap hashes from parsed scalars (fix for user-defined "JSONScalar") #304
- If a list entry has a
GraphQL::ExecutionError
, replace the entry withnil
and return the error #295
- Support graphql-batch rescuing
InvalidNullError
s #296 - Schema printer prints Enum names, not Ruby values for enums #297
- Previously-deprecated
InterfaceType#resolve_type
hook has been removed, useSchema#resolve_type
instead #290
- Eager-load schemas at definition time, validating types & schema-level hooks #289
InvalidNullError
s contain the type & field name that returned null #293- If an object is resolved with
Schema#resolve_type
and the resulting type is not a member of the expected possible types, raise an error #291
- Allow
directive
as field or argument name #288
-
GraphQL::Relay::GlobalNodeIdentification
was removed. Its features were moved toGraphQL::Schema
orGraphQL::Relay::Node
. The new hooks support more robust & flexible global IDs. #243-
Relay's
"Node"
interface andnode(id: "...")
field were both moved toGraphQL::Relay::Node
. To use them in your schema, call.field
and.interface
. For example:# Adding a Relay-compliant `node` field: field :node, GraphQL::Relay::Node.field
# This object type implements Relay's `Node` interface: interfaces [GraphQL::Relay::Node.interface]
-
UUID hooks were renamed and moved to
GraphQL::Schema
. You should defineid_from_object
andobject_from_id
in yourSchema.define { ... }
block. For example:MySchema = GraphQL::Schema.define do # Fetch an object by UUID object_from_id ->(id, ctx) { MyApp::RelayLookup.find(id) } # Generate a UUID for this object id_from_object ->(obj, type_defn, ctx) { MyApp::RelayLookup.to_id(obj) } end
-
The new hooks have no default implementation. To use the previous default, use
GraphQL::Schema::UniqueWithinType
, for example:MySchema = GraphQL::Schema.define do object_from_id ->(id, ctx) { # Break the id into its parts: type_name, object_id = GraphQL::Schema::UniqueWithinType.decode(id) # Fetch the identified object # ... } id_from_object ->(obj, type_defn, ctx) { # Provide the the type name & the object's `id`: GraphQL::Schema::UniqueWithinType.encode(type_defn.name, obj.id) } end
If you were using a custom
id_separator
, it's now accepted as an input toUniqueWithinType
's methods, asseparator:
. For example:# use "---" as a ID separator GraphQL::Schema::UniqueWithinType.encode(type_name, object_id, separator: "---") GraphQL::Schema::UniqueWithinType.decode(relay_id, separator: "---")
-
type_from_object
was previously deprecated and has been replaced bySchema#resolve_type
. You should define this hook in your schema to return a type definition for a given object:MySchema = GraphQL::Schema.define do # ... resolve_type ->(obj, ctx) { # based on `obj` and `ctx`, # figure out which GraphQL type to use # and return the type } end
-
Schema#node_identification
has been removed.
-
-
Argument
default values have been changed to be consistent withInputObjectType
default values. #267Previously, arguments expected GraphQL values as
default_value
s. Now, they expect application values. (InputObjectType
s always worked this way.)Consider an enum like this one, where custom values are provided:
PowerStateEnum = GraphQL::EnumType.define do name "PowerState" value("ON", value: 1) value("OFF", value: 0) end
Previously, enum names were provided as default values, for example:
field :setPowerState, PowerStateEnum do # Previously, the string name went here: argument :newValue, default_value: "ON" end
Now, enum values are provided as default values, for example:
field :setPowerState, PowerStateEnum do # Now, use the application value as `default_value`: argument :newValue, default_value: 1 end
Note that if you don't have custom values, then there's no change, because the name and value are the same.
Here are types that are affected by this change:
- Custom scalars (previously, the
default_value
was a string, now it should be the application value, egDate
orBigDecimal
) - Enums with custom
value:
s (previously, thedefault_value
was the name, now it's the value)
If you can't replace
default_value
s, you can also use a type's#coerce_input
method to translate a GraphQL value into an application value. For example:# Using a custom scalar, "Date" # PREVIOUSLY, provide a string: argument :starts_on, DateType, default_value: "2016-01-01" # NOW, transform the string into a Date: argument :starts_on, DateType, default_value: DateType.coerce_input("2016-01-01")
- Custom scalars (previously, the
- Support
@deprecated
in the Schema language #275 - Support
directive
definitions in the Schema language #280 - Use the same introspection field descriptions as
graphql-js
#284
- Operation name is no longer present in execution error
"path"
values #276 - Default values are correctly dumped & reloaded in the Schema language #267
- Validation errors no longer have a
"path"
key in their JSON. It was renamed to"fields"
#264 @skip
and@include
over multiple selections are handled according to the spec: if the same field is selected multiple times and one or more of them would be included, the field will be present in the response. Previously, if one or more of them would be skipped, it was absent from the response. #256
- Execution errors include a
"path"
key which points to the field in the response where the error occurred. #259 - Parsing directives from the Schema language is now supported #273
@skip
and@include
over multiple selections are now handled according to the spec #256
- Directives are no longer considered as "conflicts" in query validation. This is in conformity with the spec, but a change for graphql-ruby #263
- Query analyzers may emit errors by raising
GraphQL::AnalysisError
s during#call
or returning a single error or an array of errors from#final_value
#262
- Merge fields even when
@skip
/@include
are not identical #263 - Fix possible infinite loop in
FieldsWillMerge
validation #261
- Find infinite loops in nested contexts, too #258
GraphQL::Analysis::FieldUsage
can be used to check for deprecated fields in the query analysis phase #245
- If a schema receives a query on
mutation
orsubscription
but that root doesn't exist, return a validation error #254 Query::Arguments#to_h
only includes keys that were provided in the query or have a default value #251
GraphQL::Language::Nodes::Document#slice(operation_name)
finds that operation and its dependencies and puts them in a newDocument
#241
- Validation errors for non-existent fields have the location of the field usage, not the parent field #247
- Properly
require "forwardable"
#242 - Remove
ALLOWED_CONSTANTS
for boolean input, use a plain comparison #240
- Assign
#mutation
on objects which are derived from aRelay::Mutation
#239
- fix backward compatibility for
type_from_object
#238
- AST nodes now respond to
#eql?(other)
to test value equality #231
- The
connection
helper no longer adds a duplicate field #235
- Support parsing nameless fragments (but not executing them) #232
- Allow
__type(name: "Whatever")
to return null, as per the spec #233 - Include a Relay mutation's description with a mutation field #225
GraphQL::Schema::Loader.load(schema_json)
turns an introspection result into aGraphQL::Schema
#207.define
accepts plural definitions for: object fields, interface fields field arguments, enum values #222
-
Schema.new
is deprecated; useSchema.define
instead.Before:
schema = GraphQL::Schema.new( query: QueryType, mutation: MutationType, max_complexity: 100, types: [ExtraType, OtherType] ) schema.node_identification = MyGlobalID schema.rescue_from(ActiveRecord::RecordNotFound) { |err| "..." }
After:
schema = GraphQL::Schema.define do query QueryType mutation MutationType max_complexity 100 node_identification MyGlobalID rescue_from(ActiveRecord::RecordNotFound) { |err| "..." } # Types was renamed to `orphan_types` to avoid conflict with the `types` helper orphan_types [ExtraType, OtherType] end
This unifies the disparate methods of configuring a schema and provides new, more flexible design space. It also adds
#metadata
to schemas for user-defined storage. -
UnionType#resolve_type
,InterfaceType#resolve_type
, andGlobalNodeIdentification#type_from_object
are deprecated, unify them intoSchema#resolve_type
instead.Before:
GraphQL::Relay::GlobalNodeIdentification.define do type_from_object ->(obj) { ... } end GraphQL::InterfaceType.define do resolve_type ->(obj, ctx) { ... } end
After:
GraphQL::Schema.define do resolve_type ->(obj, ctx) { ... } end
This simplifies type inference and prevents unexpected behavior when different parts of the schema resolve types differently.
- Include expected type in Argument errors #221
- Define schemas with
Schema.define
#208 - Define a global object-to-type function with
Schema#resolve_type
#216
InvalidNullError
s expose a proper#message
#217
- Return an empty result for queries with no operations #219
Connection.new(:field)
is optional, not required #215- 0.18.2 introduced a more restrictive approach to resolving interfaces & unions; revert that approach #212
- Connection objects expose the
GraphQL::Field
that created them viaConnection#field
#206
- Unify
Relay
naming aroundnodes
as the items of a connection:Relay::BaseConnection.connection_for_nodes
replacesRelay::BaseConnection.connection_for_items
Relay::BaseConnection#nodes
replacesRelay::BaseConnection#object
- Connection fields'
.resolve_proc
is an instance ofRelay::ConnectionResolve
#204 - Types, fields and arguments can store arbitrary values in their
metadata
hashes #203
graphql-relay
has been merged withgraphql
, you should removegraphql-relay
from your gemfile. #195
GraphQL.parse
can turn schema definitions into aGraphQL::Language::Nodes::Document
. The document can be stringified again withDocument#to_query_string
#191- Validation errors include a
path
to the part of the query where the error was found #198 .define
also accepts keywords for each helper method, egGraphQL::ObjectType.define(name: "PostType", ...)
global_id_field
s have default complexity of 1, notnil
- Relay
pageInfo
is correct for connections limited bymax_page_size
- Rescue invalid variable errors & missing operation name errors during query analysis
- Correctly spread fragments when nested inside other fragments #194
- Fix
InternalRepresentation::Node#inspect
-
InternalRepresentation::Node
API changes:#definition_name
returns the field name on field nodes (while#name
may have an alias)#definitions
returns{type => field}
pairs for possible fields on this node#definition
is gone, it is equivalent tonode.definitions.values.first
#on_types
is gone, it is equivalent tonode.definitions.keys
- Accept
hash_key:
field option - Call
.define { }
block lazily, so-> { }
is not needed for circular references #182
- Support
on
as an Enum value - If the same field is requested on multiple types, choose the maximum complexity among them (not the first)
- Fix merging fragments on Union types (see #190, broken from #180)
- I don't know that this breaks anything, but
GraphQL::Query::SerialExecution
now iterates over a tree ofGraphQL::InternalRepresentation::Node
s instead of an AST (GraphQL::Language::Nodes::Document
).
- Query context keys can be assigned with
Context#[]=
#178 - Cancel further field resolution with
TimeoutMiddleware
#179 - Add
GraphQL::InternalRepresentation
for normalizing queries from AST #180 - Analyze the query before running it #180
- Assign complexity cost to fields, enforce max complexity before running it #180
- Log max complexity or max depth with
MaxComplexity
orMaxDepth
analyzers #180 - Query context exposes
#irep_node
, the internal representation of the current node #180
- Non-null errors are propagated to the next nullable field, all the way up to
data
#174
EnumValue
s can receive their properties after instantiation #171
- Support lazy type arguments in Object's
interfaces
and Union'spossible_types
#169
- Support single-member Unions, as per the spec #170
- Whitelist operation types in
lexer.rb
- Remove
debug:
option, propagate all errors. #161
-
debug:
is deprecated (#165). Propagating errors (debug: true
) will become the default behavior. You can get a similar implementation of error gobbling withCatchallMiddleware
. Add it to your schema:MySchema.middleware << GraphQL::Schema::CatchallMiddleware
- Restore previous introspection fields on DirectiveType as deprecated #164
- Apply coercion to input default values #162
- Proper Enum behavior when a value isn't found
GraphQL::Language::Nodes::Document#to_query_string
will re-serialize a query AST #151- Accept
root_value:
when running a query #157 - Accept a
GraphQL::Language::Nodes::Document
toQuery.new
(this allows you to cache parsed queries on the server) #152
- Improved parse error messages #149
- Improved build-time validation #150
- Raise a meaningful error when a Union or Interface can't be resolved during query execution #155
- "Dangling" object types are not loaded into the schema. The must be passed in
GraphQL::Schema.new(types: [...])
. (This was deprecated in 0.12.1)
- Update directive introspection to new spec #121
- Improved schema validation errors #113
- 20x faster parsing #119
- Support inline fragments without type condition #123
- Support multiple schemas composed of the same types #142
- Accept argument
description
anddefault_value
in the block #138 - Middlewares can send new arguments to subsequent middlewares #129
- Don't leak details of internal errors #120
- Default query
context
to{}
#133 - Fixed list nullability validation #131
- Ensure field names are strings #128
- Fix
@skip
and@include
implementation #124 - Interface membership is not shared between schemas #142
-
Connecting object types to the schema only via interfaces is deprecated. It will be unsupported in the next version of
graphql
.Sometimes, object type is only connected to the Query (or Mutation) root by being a member of an interface. In these cases, bugs happen, especially with Rails development mode. (And sometimes, the bugs don't appear until you deploy to a production environment!)
So, in a case like this:
HatInterface = GraphQL::ObjectType.define do # ... end FezType = GraphQL::ObjectType.define do # ... interfaces [HatInterface] end QueryType = GraphQL::ObjectType.define do field :randomHat, HatInterface # ... end
FezType
can only be discovered byQueryType
throughHatInterface
. Iffez_type.rb
hasn't been loaded by Rails,HatInterface.possible_types
will be empty!Now,
FezType
must be passed to the schema explicitly:Schema.new( # ... types: [FezType] )
Since the type is passed directly to the schema, it will be loaded right away!
-
GraphQL::DefinitionConfig
was replaced byGraphQL::Define
#116 -
Many scalar types are more picky about which inputs they allow (#115). To get the previous behavior, add this to your program:
# Previous coerce behavior for scalars: GraphQL::BOOLEAN_TYPE.coerce = ->(value) { !!value } GraphQL::ID_TYPE.coerce = ->(value) { value.to_s } GraphQL::STRING_TYPE.coerce = ->(value) { value.to_s } # INT_TYPE and FLOAT_TYPE were unchanged
-
GraphQL::Field
s can't be renamed because#resolve
may depend on that name. (This was only a problem if you pass the sameGraphQL::Field
instance tofield ... field:
definitions.) -
GraphQL::Query::DEFAULT_RESOLVE
was removed.GraphQL::Field#resolve
handles that behavior.
- Can override
max_depth:
fromSchema#execute
- Base
GraphQL::Error
for all graphql-related errors
- Include
""
for String default values (so it's encoded as a GraphQL string literal)
- Schema
max_depth:
option #110 - Improved validation errors for input objects #104
- Interfaces provide field implementations to object types #108
GraphQL::Query::BaseExecution
was removed, you should probably extendSerialExecution
instead #96GraphQL::Language::Nodes
members no longer raise if they don't get inputs duringinitialize
#92GraphQL.parse
no longer acceptsas:
for parsing partial queries. #92
Field#property
&Field#property=
can be used to access & modify the method that will be sent to the underlying object when resolving a field #88- When defining a field, you can pass a string for as
type
. It will be looked up in the global namespace. Query::Arguments#to_h
unwrapsArguments
objects recursively- If you raise
GraphQL::ExecutionError
during field resolution, it will be rescued and the message will be added to the response'serrors
key. #93 - Raise an error when non-null fields are
nil
#94
- Accept Rails params as input objects
- Don't get a runtime error when input contains unknown key #100
- Handle re-assignment of
ObjectType#interfaces
#84 - Fix merging queries on interface-typed fields #85
- Fix transform of nested lists #79
- Fix parse & transform of escaped characters #83
- Support Rubinius
- Coerce values into one-item lists for ListTypes
- Remove leftover
puts
es
- Accept enum value description in definition #71
- Correctly parse empty input objects #75
- Correctly parse arguments preceded by newline
- Find undefined input object keys during static validation
- Add
Arguments#to_h
#66
- Accept argument description in definition
- Correctly parse empty lists
- Support root-level
subscription
type
- Require Set for Schema::Printer
- Handle blank strings in queries
- Raise if a field is configured without a proper type #61
- Properly merge fields on fragments within fragments
- Properly delegate enumerable-ish methods on
Arguments
#56 - Fix & refactor literal coersion & validation #53
- Scalars can have distinct
coerce_input
andcoerce_result
methods #48 - Operations don't require a name #54
- Big refactors and fixes to variables and arguments:
- Correctly apply argument default values
- Correctly apply variable default values
- Raise at execution-time if non-null variables are missing
- Incoming values are coerced to their proper types before execution
- Add
Schema#middleware
to wrap field access - Add
RescueMiddleware
to handle errors during field execution - Add
Schema::Printer
for printing the schema definition #45
- Fields can return
GraphQL::ExecutionError
s to add errors to the response
- Fix resolution of union types in some queries #41
- Add
Schema#execute
shorthand for running queries - Merge identical fields in fragments so they're only resolved once #34
- An error during parsing raises
GraphQL::ParseError
#33
- Find nested input types in
TypeReducer
#35 - Find variable usages inside fragments during static validation
- remove Celluloid dependency
- remove
GraphQL::Query::ParallelExecution
(usegraphql-parallel
)
GraphQL::Query::ParallelExecution
has been extracted tographql-parallel
- Async field resolution with
context.async { ... }
- Access AST node during resolve with
context.ast_node
- Fix for validating arguments returning up too soon
- Raise if you try to define 2 types with the same name
- Raise if you try to get a type by name but it doesn't exist
- Merge nested results from different fragments instead of using the latest one only
- Query keyword argument
params:
was removed, usevariables:
instead.
@skip
has precedence over@include
- Handle when
DEFAULT_RESOVE
returns nil
- Fix whitespace parsing in input objects
- Parse UTF-8 characters & escaped characters
- Properly parse empty strings
- Fix argument / variable compatibility validation
- Deprecate
params
option toQuery#new
in favor ofvariables
- Deprecated
.new { |obj, types, fields, args| }
API was removed (use.define
)
Query#new
acceptsoperation_name
argumentInterfaceType
andUnionType
acceptresolve_type
configs
- Gracefully handle blank-string & whitespace-only queries
- Handle lists in variable definitions and arguments
- Handle non-null input types
- Deprecate definition API that yielded a bunch of helpers #18
- Add new definition API #18