- When using
loads:with a nullable mutation input field, allownullvalues to be provided. #1851 - When an invalid Base64 encoded cursor is provided, raise a
GraphQL::ExecutionErrorinstead ofArgumentError. #1855 - Fix an issue with
extras: [:path]would use the field'spathinstead of thecontext. #1859
- Add scalar type generator
rails g graphql:scalar#1847 - Add
#digmethod toQuery::Context#1861
- When
field ...is called with a block and the block has one argument, the field is yielded, butselfinside the block is not changed to the field. #1843
extras: [...]can inject values from the field instance #1808- Add
ISO8601DateTime.time_precisionfor 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_idwill no longer be passed toauthorized?method #1771 - Fix issue in schema upgrader script which would cause
.to_non_null_typecalls 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
StandardErroris thrown #1804
- Add
#pathmethod 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_preparewas 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_namefor overriding default logic #1729 - Add
#add_argumentfor building schemas #1732 - Cursors are decoded using
urlsafe_decode64to future-proof for urlsafe cursors #1748
- Only allow Objects to implement actual Interfaces #1715. Use
includeinstead 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_fieldoption toedge_typeto hide nodes field #1693 - Add
GraphQL::Types::ISO8601DateTimeto documentation #1694 - Conditional Analyzers #1690
- Improve error messages in
ActionCableSubscriptions#1675 - Add Prometheus tracing #1672
- Add
maptoInputObject#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_classmethod #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_methodsare 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
ISO8601DateTimeby default #1660 - Support
extendin the parser #1620 - Improve generator to have nicer error handling in development
- Fix
@skip/@includewith default value offalse#1617 - Fix lists of abstract types with promises #1613
- Don't check the type of
nilwhen it's in a list #1610 - Fix NoMethodError when
variables: nilis passed toexecute(...)#1661 - Objects returned from
Schema.unauthorized_objectsare 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_typeshelpers to abstract types #1580
- Fix
Language::Visitorwhen visitingInputObjectTypeDefinitionnodes to include childDirectivenodes. #1584 - Fix an issue preventing proper subclassing of
TimeoutMiddleware. #1579 - Fix
graphql:interfacegenerator such that it generates working code. #1577 - Update the description of auto-generated
beforeandafterarguments to better describe their input type. #1572 - Add
Language::Nodes::DirectiveLocationAST node to represent directive locations in directive definitions. #1564
Schema::InputObject#to_hrecursively transforms hashes to underscorized, symbolized keys. #1555
- Generators create class-based types #1562
Schema::InputObject#to_hreturns a underscorized, symbolized hash #1555
- Support
default_maskin class-based schemas #1563 - Fix null propagation for list types #1558
- Validate unique arguments in queries #1557
- Fix
RelayClassicMutations 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.newaccepts 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/contextin 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. UseForwardableinstead, and update your Ruby if you're on2.4.0, due to a performance regression inForwardablein that version.MySchema.subscriptions.triggerasserts 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.triggerboth 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_optionsfor how thefield(...)helper's arguments are merged to go toField.new. #1508
Schema::Resolveris a replacement forGraphQL::Function#1472- Fix subscriptions with class-based schema #1478
Tracing::NewRelicTracingacceptsset_transaction_name:to use the GraphQL operation name as the NewRelic transaction name #1430
- Backported
accepts_definitions are inherited #1514 - Fix Schema generator's
resolve_typemethod #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_mutationwas moved to an instance method; see changes toSchema::RelayClassicMutationin #1469 for an example refactor -
GraphQL::Delegatewas removed, use Ruby'sForwardableinstead (warning: bad performance on Ruby 2.4.0) -
GraphQL::Schema::Interfaceis 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
implementsas before:class EventVenue < BaseObject implements Reservable end
GraphQL::Schema::Interfaceis 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
superto 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
triggeraccepts symbol, underscored arguments and validates their presence #1400 - Mutations accept a
null(true | false)setting to affect field nullability #1406 RescueMiddlewareuses 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
.subscriptionsfor class-based Schemas #1391
- Add
Schema::MutationandSchema::RelayClassicMutationbase 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_definitionfor configurations #1357 - Add
#ownermethod to Schema objects - Add
Interface.orphan_typesconfig for orphan types #1346 - Add
extras: :execution_errorsforadd_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_typefor Union and Interface classes #1342 - Apply kwargs before block in
Argument.from_dsl#1350
- Upgrader improvements #1305
- Support
global_id_fieldfor interfaces #1299 - Add
camelize: false#1300 - Add readers for
context,objectandarguments#1283 - Replace
Schema.method_missingwith 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.valuesandInputObject.argumentsreturn 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 ... endinstance_evals on the Field instance, not a FieldProxy #1227[T, null: true]creates lists with nullable items #1229- Upgrader improvements #1223
- Don't require
parserunless the upgrader is run #1218
- Custom
Contextclasses 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
nameinstead 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_typesin error message #1380 - Use an empty hash for
resultwhen a query has unhandled errors #1382
Schema#as_jsonreturns a hash, not aGraphQL::Query::Result#1288
typed_childrenshould always return a Hash #1278
- Fix compatibility of
irep_node.typed_childrenon 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
contextto multiplex inQuery#result#1200
- Refactor
Schema::Printerto useLanguage::Printer#1159 - Add
ArgumentValue#default_used?andArguments#default_used?#1152
- Fix Scout Tracing #1187
- Call
#inspectforEnumType::UnresolvedValueError#1179 - Parse empty field sets in IDL parser #1145
Schema#to_documentreturns aLanguage::Nodes::Document#1134- Add
trace_scalarsandtrace: true|falseto monitoring #1103 - Add
Tracing::DataDogPlatformmonitoring #1129 - Support namespaces in
rails g graphql:functionand: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#inspectto#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_idhelper #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.installis 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
optionsforGraphQL::ExecutionError#1002 - Use
GlobalIDfor subscription serialization when available #1004 - Schema- and query-local, threadsafe tracers #996
- Accept symbol-keyed arguments to
.trigger#1009
- Fix arguments on
Query.__typefield #978 - Fix
Relay::Edgeobjects inBacktracetables #975
- Correctly skip connections that return
ctx.skip#972
- Properly release changes from 1.7.0
GraphQL::Resultis the returned from GraphQL execution. #898Schema#executeandQuery#resultboth return aGraphQL::Result. It implements Hash-like methods to preserve compatibility.
-
puts ctx.backtraceprints out a GraphQL backtrace table #946 -
GraphQL::Backtrace.enablewraps unhandled errors with GraphQL backtraces #946 -
GraphQL::Relay::ConnectionType.bidrectional_pagination = trueturns on true bi-directional pagination checks forhasNextPage/hasPreviousPagefields. This will become the default behavior in a future version. #960 -
Field arguments may be accessed as methods on the
argsobject. This is an alternative to#[]syntax which provides did-you-mean behavior instead of returningnilon 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.definebuilds re-usable arguments #948 -
GraphQL::Subscriptionsprovides hooks for subscription platforms #672 -
GraphQL::Subscriptions::ActionCableSubscriptionsimplements subscriptions over ActionCable #672 -
More runtime values are accessble from a
ctxobject #923 :ctx.parentreturns thectxfrom the parent fieldctx.objectreturns the currentobjfor that fieldctx.valuereturns the resolved GraphQL value for that field
These can be used together, for example,
ctx.parent.objectto get the parent object. -
GraphQL::Tracingprovides more hooks into gem internals for performance monitoring #917 -
GraphQL::Resultprovides access to the originalqueryandcontextafter 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
forwardablewhen it's not Ruby 2.4.0 #926 - Improve
UnresolvedTypeErrormessage #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_classtonil#942 - Disallow invalid enum values #915
- Disallow doubly-nested non-null types #916
- Fix
Query#selected_operation_namewhen no selections are present #899 - Fix needless
COUNTquery forhasNextPage#906 - Fix negative offset with
lastargument #907 - Fix line/col for
ArgumentsAreDefinedvalidation #890 - Fix Sequel error when limit is
0#892
- Add
GraphQL.parse_fileandAbstractNode#filename#873 - Support
.graphqlfilepaths withSchema.from_definition#872
- Fix variable usage inside non-null list #888
- Fix unqualified usage of ActiveRecord::Relation #885
- Fix
FieldsWillMergehandling of equivalent input objects - Fix to call
prepare:on nested input types
- Validate
graphql-prodownloads withrake graphql:pro:validate[$VERSION]#846
- Remove usage of Rails-only
Array.wrap#840 - Fix
RelationConnectionto count properly when relation contains an alias #838 - Print name of Enum type when a duplicate value is added #843
-
Schema#types[](type_name)returnsnilwhen there's no type namedtype_name(it used to raiseRuntimeError). To get an error for missing types, use.fetchinstead, 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_typesorSchema#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_typeis now called with(abstract_type, obj, ctx)instead of(obj, ctx)#834 . To update, add an unused parameter to the beginning of yourresolve_typehook:MySchema = GraphQL::Schema.define do # Old way: resolve_type ->(obj, ctx) { ... } # New way: resolve_type ->(type, obj, ctx) { ... } end
rails g graphql:mutationwill add Mutation boilerplate if it wasn't added already #812InterfaceTypeandUnionTypeboth acceptresolve_type ->(obj, ctx) { ... }functions for type-specific resolution. This function takes precedence overSchema#resolve_type#829 #834Schema#resolve_typeis 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_complexityoverrides #812 - Return a client error when
InputObjectTypereceives an array as input #803 - Properly handle raised errors in
preparefunctions #805 - Fix using
asandprepareinargument do ... endblocks #817 - When types are added to the schema with
instrument(:field, ...), make sure they're inSchema#types#819 - Raise an error when duplicate
EnumValueis 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_definitionsorts fields and arguments alphabetically #775validate: falseskips static validations in query execution #790
graphql:installaddsoperation_name: params[:operationName]#786graphql:installskipsgraphiql-railsfor API-only apps #772SerialExecutioncalls.is_a?(Skip)to avoid user-defined#==methods #794prepare:functions which returnExecutionErrorare 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
Methods 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_sizewhen 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_strategywhen executing a single query (doesn't supportSchema#multiplex) #755 - Fix NameError when
ActiveRecordisn't loaded #747 - Fix
Query#mutation?etc to support lazily-loaded AST #754
Query#selected_operation_namereturns the operation to execute, even if it was inferred (not provided asoperation_name:) #746
- Return
nilfromQuery#operation_nameif nooperation_name:was provided #746
-
InternalRepresentation::Node#return_typewill now return the wrapping type. Usereturn_type.unwrapto 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_queryandafter_queryhooks to separate instrumenters. -
In a
Relay::Mutation, Raising or returning aGraphQL::Executionwill nullify the mutation field, not the field's children. #731 -
args.to_hreturns a slightly different hash #714- keys are always
Strings - if an argument is aliased with
as:, the alias is used as the key
- keys are always
-
InternalRepresentation::Node#return_typeincludes the original "wrapper" types (non-null or list types), call.unwrapto get the inner type #20# before irep_node.return_type # after irep_node.return_type.unwrap
-
Argument
preparefunctions 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::RakeTasksupports dumping the schema to IDL or JSON #687- Improved support for
Schema.from_definition#699 :- Custom scalars are supported with
coerce_inputandcoerce_resultfunctions resolve_typefunction will be used for abstract types- Default resolve behavior is to check
objfor a method and call it with 0, 1, or 2 arguments.
- Custom scalars are supported with
ctx.skipmay 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
preparefunctions are invoked with(val, ctx)(previously, it was only(val)) #730 args.to_hreturns stringified, aliased arguments #714ctx.namespace(:my_namespace)provides namespaced key-value storage #689GraphQL::Querycan 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_sizeinRelay::RelationConnectionandRelay::ArrayConnection#728 - Nullify a mutation field when it raises or returns an error #731
UniqueWithinTypeRelay ID generator supports-in the ID #742assign_metadata_keyassignstruewhen the definition method is called without arguments #724- Improved lexer performance #737
- Assign proper
parentwhen aconnectionresolve returns a promise #736
- Fix raising
ExecutionErrorinside mutation resolve functions (it nullifies the field) #722
- Fix returning
nilfrom connection resolve functions (now they becomenull) #719 - Fix duplicate AST nodes when merging fragments #721
Schema.from_definitionaccepts aparser:option (to work around lack of schema parser ingraphql-libgraphqlparser) #712Query#internal_representationexposes 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_nameto 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#encodefor 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_resolveinstrumentation forconnectionfields #679
InternalRepresentation::Node#definitionreturnsnilinstead of raising NoMethodError for operation fields #675Field#functionis properly populated for fields derived fromGraphQL::Functions #674
-
Returned strings which aren't encoded as UTF-8 or ASCII will raise
GraphQL::StringEncodingErrorinstead of becomingnil#661To preserve the previous behavior, Implement
Schema#type_errorto returnnilfor this error, eg:GraphQL::Schema.define do type_error ->(err, ctx) { case err # ... when GraphQL::StringEncodingError nil end }
-
coerce_non_null_inputandvalidate_non_null_inputare private #667
-
One-argument
coerce_inputandcoerce_resultfunctions 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_inputwithout actxis deprecated. #667 Usecoerce_isolated_resultcoerce_isolated_input,valid_isolated_input?,validate_inputto explicitly bypassctx.
- Include
#typesinGraphQL::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
#executeto avoid messing with Rails constant loading #665
- Improve threadsafety of
lazy_resolvecache, useConcurrent::Mapif it's available #631 - Properly handle unexpeced input objects #638
- Handle errors during definition by preseriving the definition #632
- Fix
nilinput 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
nilmembers 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#parentand 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_errorto raise the error:MySchema = GraphQL::Schema.define do # ... parse_error ->(err, ctx) { raise(err) } end
- Add
graphq:enumgenerator #611 - Parse errors are returned to the client instead of raised #607
- Handle negative cursor pagination args as
0#612 - Properly handle returned
GraphQL::ExecutionErrors 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_definitiondefault resolver hashes to have defaults #608
- Fix rewrite performance regressions from 1.5.0 #599
- Remove unused
GraphQL::Execution::Lazyinitialization API #597
-
Only UTF-8-encoded strings will be returned by
Stringfields. Strings with other encodings (or objects whose#to_smethod returns a string with a different encoding) will returnnilinstead 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_typealways returns an object type. (Interfaces and Unions are replaced with concrete object types which are valid in the current scope.)
See changes to
Analysis::QueryComplexityfor an example migration. Here are some other specific changes:- Nodes are tracked on object types only, not interface or union types
- Deprecated, buggy
Node#childrenandNode#pathwere removed - Buggy
#includedwas removed - Nodes excluded by directives are entirely absent from the rewritten tree
- Internal
InternalRepresentation::Selectionwas removed (no longer needed) Node#spreadswas replaced byNode#ast_spreadswhich returns a Set
Schema#validatereturns a list of errors for a query string #513implements ...adds interfaces to object types without inherit-by-default #548, #574GraphQL::Relay::RangeAddfor implementingRANGE_ADDmutations #587use ...definition method for plugins #565- Rails generators #521, #580
GraphQL::Functionfor reusable resolve behavior with arguments & return type #545- Support for Ruby 2.4 #475
- Relay
node&nodesfield can be extended with a custom block #552 - Performance improvements:
- Resolve fragments only once when validating #504
- Reuse
Argumentsobjects #500 - Skip needless
FieldResults #482 - Remove overhead from
ensure_defined#483 - Benchmark & Profile tasks for gem maintenance #520, #579
- Fetch
has_next_pagewhile 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
@skipped nodes when parallel branches are not skipped #536 - Fix offset in ArrayConnection when it's larger than the array #571
- Add missing
frozen_string_literalcomments #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.fieldandRelay::Node.plural_fieldaccept a customresolve:argument #550Relay::BaseConnection#contextprovides access to the query context #537- Allow re-assigning
Field#name#541 - Support
return_interfacesonRelay::Mutations #533 BaseType#to_definitionstringifies 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_types #535 - Better error when
Relay::Mutation.resolvedoesn't return a Hash
GraphQL::Relay::Node.plural_fieldfinds 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
lastonly #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
#callmethods has changed. Instead ofnext_middlewarebeing the last argument, it is passed as a block. To update, callyieldto continue the middleware chain or use&next_middlewareto capturenext_middlewareinto 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
nodesfield directly to a connection. #451 That way you can say{ friends { nodes } }instead of{ freinds { edges { node } } }. Either passnodes_field: truewhen defining a custom connection type, for example:FriendsConnectionType = FriendType.define_connection(nodes_field: true)
Or, set
GraphQL::Relay::ConnectionType.default_nodes_field = truebefore 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_middlewareis now passed as a block. In general,yieldis faster than calling a captured block. -
Improve error messages for wrongly-typed variable values #423
-
Cache the value of
resolve_typeper object per query #462 -
Pass
ctxto schema filters #463 -
Accept whitelist schema filters as
only:#463 -
Add
Schema#to_definitionwhich acceptsonly:/except:to filter the schema when printing #463 -
Add
Schema#default_maskas 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
lastwithoutbefore#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_resolveallows you to define handlers for a second pass of resolution #386Field#lazy_resolvecan be instrumented to track lazy resolution #429Schema#type_errorallows you to handleInvalidNullErrors andUnresolvedTypeErrorsin your own way #416Schema#cursor_encodercan be specified for transforming cursors from built-in Connection implementations #345- Schema members
#dupcorrectly: they shallowly copy their state into new instances #444 Query#provided_variablesis 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: truewhen serializing values (to support non-stdlibJSONs) #449 - Calling
#redefineon a Schema member copies state outside of previous#defineblocks (uses#dup) #444
- Preserve connection behaviors after
redefine#421 - Implement
respond_to_missing?onDefinedObjectProxy(which isselfinside.define { ... }) #414
Visitorreceived some breaking changes, though these are largely-private APIs (#401):- Global visitor hooks (
Visitor#enterandVisitor#leave) have been removed - Returning
SKIPfrom a visitor hook no longer skips sibling nodes
- Global visitor hooks (
Schema#instrumentmay 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_fieldsshould trigger lazy definition #392ObjectType#connectiondoesn't modify the providedGraphQL::Field#411Mutation#resolvemay return aGraphQL::ExecutionError#405Argumentscan 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
Lexerprevious token should be a local variable, not a method attribute #396Argumentsshould wrap values according to their type, not their value #398
Schema.executeraises an error ifvariables:is a string
- Dynamic fields
__schema,__typeand__typenameare properly validated #391
- Implement
Query::Context#strategyandFieldResolutionContext#strategyto 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
Noderesponds 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:inner2which has one definition (on the return type ofinner1)inner3which has one definition (on the return type ofinner1)
This can be wrong for some cases. For example, if
AandBare mutually exclusive (both object types, or union types with no shared members), theninner2andinner3will never be executed together.Now, the visit goes like this:
outerwhich has two entries intyped_children, one onAand another onB. Visit eachtyped_chidrenbranch:inner1, then its onetyped_childrenbranch:inner2
inner1, then its onetyped_childrenbranch:inner3
As you can see, we visit
inner1twice, once for each type condition.inner2andinner3are no longer visited as siblings. Instead they're visited as ... cousins? (They share a grandparent, not a parent.)Although
Node#childrenis still present, it may not contain all children actually resolved at runtime, since multipletyped_childrenbranches 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, seeQueryComplexityfor an example.You can see PR #373 for how built-in analyzers were changed to reflect this.
InternalRepresentation::Node#childrenandInternalRepresentation::Node#definitionsare deprecated due to the bug described below and the breaking change described above. Instead, useInternalRepresentation::Node#typed_childrenandInternalRepresentation::Node#defininition. #373
-
nullsupport 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_separatormay be assigned to a custom value #381 -
Context#add_error(err)may be used to add aGraphQL::ExecutionErrorto the response's"errors"key (and the resolve function can still return a value) #367 -
The third argument of
resolveis 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#contextmethod 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
Awould resolveinner1, then the result would receive bothinner2andinner3. The same was true for an object of typeB.Now, those are properly distinguished. An object of type
Aresolvesinner1, then its result receivesinner2. An object of typeBreceivesinner1, 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::ParserTestswas removed, useGraphQL::Compatibilityinstead. #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::Schemaout 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::Compatibilitycontains.build_suitefunctions 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#instrumentprovides an avenue for observing query and field resolution with no overhead.- Some
SerialExecutionobjects were converted to functions, resulting in a modest performance improvement for query resolution.
NonNullTypeandListTypehave 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: falseoption removed fromSchema.execute(it didn't work anyways) #338- Some deprecated methods were removed: #349
BaseConnection#objectwas removed, useBaseConnection#nodesBaseConnection.connection_for_itemswas removed, useBaseConnection#connection_for_nodes- Two-argument resolve functions for
Relay::Mutations are not supported, use three arguments instead:(root_obj, input, ctx) Schema.newno longer accepts initialization options, useSchema.defineinsteadGraphQL::ObjectType::UnresolvedTypeErrorwas removed, useGraphQL::UnresolvedTypeErrorinstead
- Fragment type conditions should be parsed as
TypeNamenodes, not strings. (Users ofgraphql-libgraphqlparsershould update to1.0.0of that gem.) #342
- Set
ast_nodeandirep_nodeon query context before sending it to middleware #348 - Enum values can be extended with
.define#341
- Use
RelationConnectionfor Rails 3 relations (which also extendArray) #343 - Fix schema printout when arguments have comments #335
Relay::BaseConnection#orderwas removed (it always returnednil) #313- In the IDL, Interface names & Union members are parsed as
TypeNamenodes 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_middlewareto a schema if it's not usingrescue_from#328 Query::Arguments#each_valueyieldsQuery::Argument::ArgumentValueinstances 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
cursorfor a node which isn't present in the connection's members #327
GraphQL::Query::Arguments.newrequiresargument_definitions:of type{String => GraphQL::Argument }#304
-
Relay::Mutation#resolvehas a new signature. #301Previously, it was called with two arguments:
resolve ->(inputs, ctx) { ... }
Now, it's called with three inputs:
resolve ->(obj, inputs, ctx) { ... }
objis 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::Mutationaccepts a user-definedreturn_type#310Relay::Mutation#resolvereceives theroot_valuepassed toSchema#execute#301- Derived
Relayobjects have descriptions #303
- Introspection query is 7 levels deep instead of 3 #308
- Unknown variable types cause validation errors, not runtime errors #310
Query::Argumentsdoesn't wrap hashes from parsed scalars (fix for user-defined "JSONScalar") #304
- If a list entry has a
GraphQL::ExecutionError, replace the entry withniland return the error #295
- Support graphql-batch rescuing
InvalidNullErrors #296 - Schema printer prints Enum names, not Ruby values for enums #297
- Previously-deprecated
InterfaceType#resolve_typehook has been removed, useSchema#resolve_typeinstead #290
- Eager-load schemas at definition time, validating types & schema-level hooks #289
InvalidNullErrors contain the type & field name that returned null #293- If an object is resolved with
Schema#resolve_typeand the resulting type is not a member of the expected possible types, raise an error #291
- Allow
directiveas field or argument name #288
-
GraphQL::Relay::GlobalNodeIdentificationwas removed. Its features were moved toGraphQL::SchemaorGraphQL::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.fieldand.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_objectandobject_from_idin 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_objectwas 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_identificationhas been removed.
-
-
Argumentdefault values have been changed to be consistent withInputObjectTypedefault values. #267Previously, arguments expected GraphQL values as
default_values. Now, they expect application values. (InputObjectTypes 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_valuewas a string, now it should be the application value, egDateorBigDecimal) - Enums with custom
value:s (previously, thedefault_valuewas the name, now it's the value)
If you can't replace
default_values, you can also use a type's#coerce_inputmethod 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
@deprecatedin the Schema language #275 - Support
directivedefinitions 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 @skipand@includeover 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
@skipand@includeover 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::AnalysisErrors during#callor returning a single error or an array of errors from#final_value#262
- Merge fields even when
@skip/@includeare not identical #263 - Fix possible infinite loop in
FieldsWillMergevalidation #261
- Find infinite loops in nested contexts, too #258
GraphQL::Analysis::FieldUsagecan be used to check for deprecated fields in the query analysis phase #245
- If a schema receives a query on
mutationorsubscriptionbut that root doesn't exist, return a validation error #254 Query::Arguments#to_honly 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_CONSTANTSfor boolean input, use a plain comparison #240
- Assign
#mutationon 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
connectionhelper 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.defineaccepts plural definitions for: object fields, interface fields field arguments, enum values #222
-
Schema.newis deprecated; useSchema.defineinstead.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
#metadatato schemas for user-defined storage. -
UnionType#resolve_type,InterfaceType#resolve_type, andGlobalNodeIdentification#type_from_objectare deprecated, unify them intoSchema#resolve_typeinstead.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
InvalidNullErrors 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::Fieldthat created them viaConnection#field#206
- Unify
Relaynaming aroundnodesas the items of a connection:Relay::BaseConnection.connection_for_nodesreplacesRelay::BaseConnection.connection_for_itemsRelay::BaseConnection#nodesreplacesRelay::BaseConnection#object
- Connection fields'
.resolve_procis an instance ofRelay::ConnectionResolve#204 - Types, fields and arguments can store arbitrary values in their
metadatahashes #203
graphql-relayhas been merged withgraphql, you should removegraphql-relayfrom your gemfile. #195
GraphQL.parsecan turn schema definitions into aGraphQL::Language::Nodes::Document. The document can be stringified again withDocument#to_query_string#191- Validation errors include a
pathto the part of the query where the error was found #198 .definealso accepts keywords for each helper method, egGraphQL::ObjectType.define(name: "PostType", ...)
global_id_fields have default complexity of 1, notnil- Relay
pageInfois 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::NodeAPI changes:#definition_namereturns the field name on field nodes (while#namemay have an alias)#definitionsreturns{type => field}pairs for possible fields on this node#definitionis gone, it is equivalent tonode.definitions.values.first#on_typesis 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
onas 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::SerialExecutionnow iterates over a tree ofGraphQL::InternalRepresentation::Nodes 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::InternalRepresentationfor 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
MaxComplexityorMaxDepthanalyzers #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
EnumValues can receive their properties after instantiation #171
- Support lazy type arguments in Object's
interfacesand 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_stringwill re-serialize a query AST #151- Accept
root_value:when running a query #157 - Accept a
GraphQL::Language::Nodes::DocumenttoQuery.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
descriptionanddefault_valuein the block #138 - Middlewares can send new arguments to subsequent middlewares #129
- Don't leak details of internal errors #120
- Default query
contextto{}#133 - Fixed list nullability validation #131
- Ensure field names are strings #128
- Fix
@skipand@includeimplementation #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
FezTypecan only be discovered byQueryTypethroughHatInterface. Iffez_type.rbhasn't been loaded by Rails,HatInterface.possible_typeswill be empty!Now,
FezTypemust 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::DefinitionConfigwas 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::Fields can't be renamed because#resolvemay depend on that name. (This was only a problem if you pass the sameGraphQL::Fieldinstance tofield ... field:definitions.) -
GraphQL::Query::DEFAULT_RESOLVEwas removed.GraphQL::Field#resolvehandles that behavior.
- Can override
max_depth:fromSchema#execute - Base
GraphQL::Errorfor 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::BaseExecutionwas removed, you should probably extendSerialExecutioninstead #96GraphQL::Language::Nodesmembers no longer raise if they don't get inputs duringinitialize#92GraphQL.parseno 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_hunwrapsArgumentsobjects recursively- If you raise
GraphQL::ExecutionErrorduring field resolution, it will be rescued and the message will be added to the response'serrorskey. #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
putses
- 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
subscriptiontype
- 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_inputandcoerce_resultmethods #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#middlewareto wrap field access - Add
RescueMiddlewareto handle errors during field execution - Add
Schema::Printerfor printing the schema definition #45
- Fields can return
GraphQL::ExecutionErrors to add errors to the response
- Fix resolution of union types in some queries #41
- Add
Schema#executeshorthand 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::ParallelExecutionhas 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.
@skiphas precedence over@include- Handle when
DEFAULT_RESOVEreturns nil
- Fix whitespace parsing in input objects
- Parse UTF-8 characters & escaped characters
- Properly parse empty strings
- Fix argument / variable compatibility validation
- Deprecate
paramsoption toQuery#newin favor ofvariables - Deprecated
.new { |obj, types, fields, args| }API was removed (use.define)
Query#newacceptsoperation_nameargumentInterfaceTypeandUnionTypeacceptresolve_typeconfigs
- 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