- Bug Fix: Remove build artifact from hex release.
- Bug Fix: Correctly compute complexity for documents with inline fragments.
- Bug Fix: Add missing
Absinthe.Subscription.child_spec/1
function - Bug Fix: Pass options along when exporting schema json.
- Enhancement: Support for Elixir 1.7.0
- Bug Fix: Fixes performance issue where deeply nested inputs used exorbitant amounts of memory.
- Bug Fix: Fixes shard routing issue with subscription pubsub
- Bug Fix: Ensure project is compiled when running absinthe mix tasks
- Bug Fix:
import_types Foo.{Bar, Baz}
syntax should avoid compilation order issues - Enhancement: Context and root value handling is broken out now to facilitate improvements in Absinthe Plug
- Bug Fix: Proper GraphQL context handling in subscriptions
- Doc Improvements
- Formatter Improvements
- Bug Fix: Dataloader won't explode if a given pass uses only already cached values
- Bug Fix: Update
result_selection_t
typespec. - Feature: Added
.formatter.exs
for use with Elixir v1.6'smix format
. - Chore: Type fixes and updated links in README and documentation.
- Feature: Support for
meta
macro keyword list args.
- Feature: Support for
"""
-quoted block strings, as defined in the GraphQL Specification (See graphql/graphql-spec#327).
- Bug Fix: fix where self referential interface type would cause infinite loop when introspecting.
- Bug Fix: fix regression where types only connected to the root query via interfaces wouldn't show up in GraphiQL.
- Bug Fix:
null
can be properly used for enum inputs.
- Bug Fix: fix regression where interfaces wouldn't show up in GraphiQL unless used as a field return type.
-
Bug Fix: Ensured types that aren't used by the schema's root types aren't reported by introspection
-
Internal Change: Added
Absinthe.Schema.used_types
,Absinthe.Schema.introspection_types/1
, andType.introspection?/1
-
Enhancement: Subscriptions! See the Absinthe.Phoenix project for getting started info.
-
Enhancement: Null literal support as laid out in the October 2016 GraphQL Specification
-
Enhancement: Errors now include path information. This path information can be accessed in resolvers via
Absinthe.Resolution.path/1
-
Breaking Change: Default middleware applied eagerly. If you're changing the default resolver, you WILL need to consult: #403 See: https://hexdocs.pm/absinthe/1.4.0-rc.3/Absinthe.Schema.html#replace_default/4
-
Breaking Change: Plugins receive an
%Absinthe.Blueprint.Execution{}
struct instead of the bare accumulator. This makes it possible for plugins to set or operate on context values. Upgrade you plugins! Change this:def before_resolution(acc) do acc = # doing stuff to the acc here end def after_resolution(acc) do acc = # doing stuff to the acc here end def pipeline(pipeline, acc) do case acc do # checking on the acc here end end
to
def before_resolution(%{acc: acc} = exec) do acc = # doing stuff to the acc here %{exec | acc: acc} end def after_resolution(%{acc: acc} = exec) do acc = # doing stuff to the acc here %{exec | acc: acc} end def pipeline(pipeline, exec) do case exec.acc do # checking on the acc here end end
The reason for this is that you can also access the
context
within theexec
value. When using something like Dataloader, it's important to have easy to the context -
Breaking Change: Errors returned from resolvers no longer say "In field #{field_name}:". The inclusion of the path information obviates the need for this data, and it makes error messages a lot easier to deal with on the front end.
-
Internal Change:
Absinthe.Blueprint.Document.Resolution
=>Absinthe.Blueprint.Execution
. See #409 for details.
- Bug Fix: Handle OTP 20.0 warnings.
- Bug Fix: Ensure
%Absinthe.Resolution{}
struct can be inspect insideresolve_type
and similar. - Bug Fix: Handle
nil
return values fromresolve_type
-
Enhancement: Improved nested fragment handling when merging is required.
-
Enhancement: Performance improvements, particularly for documents containing fragments
-
Enhancement:
Absinthe.Resolution.project/1,2
which returns the child fields under the current field. This is an improvement upon the previous recommendation, which was to get child fields via using internal data structures found in info, and required manual handling of type conditions. -
NOTE: If you were previously computing subfields by looking at
%Absinthe.Blueprint.Document.Field{}
internals, do note that their structure has changed a little. Notably, there is no longer a:fields
key.
-
Added
Absinthe.Logger
-- adds configurable pipeline and variable logging with filtering support (filters "token" and "password" by default). Used by theabsinthe_plug
package. -
Enhancement: Added resolution middleware. See the
Absinthe.Middleware
moduledocs. -
Enhancement: Middleware can be used to change the context. Use this judiciously.
-
Enhancement: Added built-in date and time types. Simply
import_types Absinthe.Type.Custom
in your schema to use. -
Enhancement: Error tuple values can now be anything that's compatible with
to_string/1
-
Enhancement: Substantial performance improvements for type conditions and abstract type return values
-
Enhancement: Added
Absinthe.Pipeline.replace/3
for easier modification of pipeline phases. -
Enhancement: Scalar and Enum serialization moved to the
Absinthe.Phase.Document.Result
phase, making customization of serialization easier. -
Bug Fix: All interfaces an object claims to implement are checked at compile time, instead of just the first.
-
Breaking change: Plugins have been replaced by middleware, see the middleware docs.
-
Breaking change:
default_resolve
is no longer valid, seeAbsinthe.Middleware
. -
Breaking change: A root
query
object is now required, per the GraphQL spec. -
Breaking change:
Absinthe.Type.Interface.implements/2
is nowimplements/3
with the last argument being the schema. -
Cleanup: Undocumented module
InterfaceMap
removed as it was no longer being used.
- Enhancement: Query complexity analysis!
- Bug fix: Fields with runtime errors are presented with
null
values in the result data instead of elided entirely.
- Enhancement: Scalar type parse functions can access the context. This enables uploaded files with Absinthe.Plug
- Enhancement: Complex errors. You can now return
{:error, %{message: "...", other_key: value}}
- Bug Fix: Invalid Arguments on a field that is under a list field doesn't error.
- Bug Fix: Deeper fragment merging.
- Bug Fix: When there are no arguments, an empty map should be passed to the resolution functions not
nil
- Enhancement: Enable
import_fields
for input objects. In the future we will enforce thatinput_objects
can only import fields from otherinput_objects
. - Enhancement: Improved exception when returning
nil
from a field markednon_null
- Enhancement: Allow returning complex errors from resolution functions.
- Enhancement: Minor tweaks to support the in-progress Elixir 1.4 release
- Bug fix: Handle fragments on the root query and root mutation types
- Bug fix: Handle errors on variables when no operation name.
- Bug fix: input objects passed in as variables with missing internal fields marked non null are correctly caught
- Assorted other bug fixes
- Stricter, spec-compliant scalar parsing rules (#194)
- Bug fix: Fixes to complex resolution using abstract types (#197) (#199)
- Bug fix: Fix escaped characters in input literals (#165) (#202)
- Bug fix: Fix regression where nested list input types did not work (#205)
Absinthe now generates a richer "intermediate representation" of query
documents (see Absinthe.Blueprint
) from the document AST. This representation
then serves as the data backbone for processing during later phases.
Rather than the integrated validation-during-execution approach used in
previous versions-- and rather than using a few "fat" phases (eg, "Parsing",
"Validation", "Execution") as in other implementations -- Absinthe treats
all operations (parsing, each individual validation, field resolution, and
result construction) as a pipeline (see Absinthe.Pipeline
) of discrete
and equal phases. This allows developers to insert, remove, switch-out, and
otherwise customize the changes that occur to the intermediate representation,
and how that intermediate representation turns into a result. Future releases
will further this model and continue to make it easier to modify Absinthe's
processing to support the unique needs of developers.
Absinthe no longer automatically adds deprecations to result errors. (Although this is possible with the addition of custom phases.)
Absinthe now more closely adheres to the GraphQL specification's rules about input value coercion, to include:
- Int: Disallowing automatic coercion of, eg,
"1"
to1
- String: Disallowing automatic coercion of, eg,
1
to"1"
- Enum: Disallowing quoted values, eg,
"RED"
vsRED
Furthermore scalar type parse
functions now receive their value as
Absinthe.Blueprint.Input.t
structs. If you have defined your own
custom scalar types, you may need to modify them; see
lib/absinthe/type/built_ins/scalars.ex
for examples.
In accordance with the GraphQL Specification, if any errors are added
during document validation, no resolution will occur. In the past,
because validation was done on-the-fly during resolution, partial
resolution, just returning null
for fields (in a way that would be
invalid, according to the spec) was possible.
(Notably, this release includes a very large number of new document validations.)
The raw AST nodes are no longer provided as part of the "info" argument passed
to resolve functions. If you have built logic (eg, Ecto preloading) based on
the AST information, look at the definition
instead, which is a Blueprint
Field
struct containing a fields
array of subfields. These fields have
passed validation and have been flattened from any fragments that may have
been used in the original document (you just may want to pay attention to
each field's type_conditions
).
Fields and arguments with list types are now automatically coerced if given a
single item. For example if you have arg :ids, list_of(:id)
Absinthe will coerce
a document like foo(ids: 1)
into foo(ids: [1])
.
This is also true for resolution functions. If your field has a return type of
list_of(:user)
and your resolution function returns {:ok, %User{}}
, the value
is wrapped. It is as though you returned {:ok, [%User{}]}
.
Adapters now only use to_internal_name/2
and to_external_name/2
as the
Absinthe.Blueprint
intermediate representation and schema application
phase removes the need for whole document conversion. If you have defined
your own adapter, you may need to modify it.
The IDL generating mix task (absinthe.schema.graphql
) has been temporarily
removed (due to the extent of work needed to modify it for this release), but
it will reappear in a future release along with integrated schema compilation
from GraphQL IDL.
Support for 3-arity resolution functions. Resolution functions accepting 3 arguments will have the current "source" (or parent) object passed as the first argument. 2-arity resolution functions will continue to be supported.
The following resolutions functions are equivalent:
fn source, args, info -> {:ok, source.foo} end
fn args, %{source: source} -> {:ok, source.foo} end
v1.2 features a Resolution Plugin mechanism. See the docs in the
Absinthe.Resolution.Plugin
module for more information.
In previous versions, the last argument to resolution functions was an
Absinthe.Execution.Field
struct. It is now an Absinthe.Resolution
struct.
While the struct has most of the same information available, the AST nodes
is no longer provided. See "Breaking Changes" above.
To further support extensibility, types and fields can be annotated using the
Absinthe.Schema.Notation.meta/2
macro, and metadata extracted using
Absinthe.Type.meta/1
and Absinthe.Type.meta/1
. This metadata facility has
been added for objects, input objects, enums, scalars, unions, interfaces, and
fields.
- Fix execution of nested fragment spreads with abstract condition types.
- Support adapting InterfaceDefinition structs; caused a warning when
running the
absinthe.schema.graphql
mix task. - Fix missing newline after scalar type definitions in IDL output by
the
absinthe.schema.graphql
mix task.
- Correctly stringify serialized default values when introspecting
- Fix bug where fragments with abstract type conditions were not applied in some cases
- Correctly serialize default values based on the underlying type for introspection
- Fix regression where documents containing multiple operations could not have the operation selected
- Fix issues with returning union types.
- Fix bug where field names inside argument errors were not returned in the adapted format.
absinthe.schema.json
now requires schema to be given as an--schema
option, but supports the:absinthe
:schema
application configuration value.absinthe.schema.graphql
task added.
- Include
priv/
in package forabsinthe.schema.json
task.
- Variables with input objects and lists inside other input objects work properly.
The v1.1.0 release bundles a bunch of bugfixes and expanded features for Absinthe, especially around:
- Support for expanding notation in other packages
- Complex arguments and variables
- An
absinthe.schema.json
mix task to extract a JSON representation of a schema for additional tooling (especially Absinthe.Relay. - Custom default resolvers, and more!
In terms of breaking changes, there is one you should know about:
As of v1.1.0, Absinthe, by default, adheres to the specification recommendation
that enum values be provided in ALLCAPS. If you have existing enum definitions
in your schema that have not explicitly declared how values should be accepted,
see the documentation for the Absinthe.Schema.Notation.enum/3
macro,
especially the use of :as
, eg:
enum :color do
value :red, as: "r"
value :green, as: "g"
value :blue, as: "b"
end
Our v1.0.0 release offers an entirely new way of build schemas. This new approach uses macros -- to simplify the visual complexity of schemas, provide more comprehensive feedback on correctness, and increase performance, since we can now execute any necessary checks and transformations during compilation.
Here's an example of an object definition in the old notation style:
@absinthe :type
def car do
%Absinthe.Type.Object{
description: "A car",
fields: fields(
picture_url: [
type: :string,
description: "Photo URL"
args: args(
size: [
type: non_null(:string),
description: "The size of the photo"
]
),
resolve: fn %{size: size}, %{source: car} ->
{:ok, "http://images.example.com/cars/#{car.id}-#{size}.jpg"}
end
]
)
}
end
Here it is in the new style:
@desc "A car"
object :car do
@desc "Photo URL"
field :picture_url, :string do
@desc "The size of the photo"
arg :size, non_null(:string)
resolve fn %{size: size}, %{source: car} ->
{:ok, "http://images.example.com/cars/#{car.id}-#{size}.jpg"}
end
end
end
In general, attributes of types are now available as nested macros
(eg, resolve
above), and attributes that are plural have a singular form
(eg, previously you passed a :fields
value and used a fields/1
convenience
function; now you use the singular field
macro to define each individual
field).
In the past, this is how you would import types from another module:
defmodule Types do
use Absinthe.Type.Definitions
# ...
end
defmodule Schema do
use Absinthe.Schema, type_modules: [Types]
# ...
end
This is how it is done now:
defmodule Types do
use Absinthe.Schema.Notation
# ...
end
defmodule Schema do
use Absinthe.Schema
import_types Types
# ...
end
Since much of the moving parts have been changed, please read through the documentation generally -- and recommend any specific instructions that you think make sense to be included in the changelog.
The following changes are required if you're upgrading from the previous version:
The second argument passed to resolution functions has changed from
Absinthe.Execution.t
to a flatter, simpler data structure,
Absinthe.Resolution.t
. This struct will be a more carefully curated
selection of metadata and match more closely to values in the JS
reference implementation.
See the typedoc for information about Absinthe.Resolution.t
, and change
any advanced resolvers to use this new struct. The most likely change will be
the use of source
instead of resolution.target
.
The following changes are required if you're upgrading from the previous version:
Instead of providing a map to :values
, use the values/1
convenience function from Absinthe.Type.Definitions
:
Before:
%Type.Enum{
values: %{
"foo" => :f,
"bar" => :b
}
}
Now:
%Type.Enum{
values: values(
foo: [value: :f],
bar: [value: :b]
)
}
This allows us to support :description
and deprecated values as used elsewhere. See Absinthe.Type.Enum
for more information.
The following changes are required if you're upgrading from the previous version:
If using Absinthe.Adapters.Passthrough
, you must manually configure it,
as explained in the README, now that the default has
changed to Absinthe.Adapters.LanguageConventions
.