absinthe on hex

1.3.2 (23 Jun 2017 15:06)

GraphQL for Elixir




  • Bug Fix: Handle OTP 20.0 warnings.
  • Bug Fix: Ensure %Absinthe.Resolution{} struct can be inspect inside resolve_type and similar.
  • Bug Fix: Handle nil return values from resolve_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 the absinthe_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, see Absinthe.Middleware.

  • Breaking change: A root query object is now required, per the GraphQL spec.

  • Breaking change: Absinthe.Type.Interface.implements/2 is now implements/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 that input_objects can only import fields from other input_objects.
  • Enhancement: Improved exception when returning nil from a field marked non_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.

Breaking Changes

Deprecations and Errors

Absinthe no longer automatically adds deprecations to result errors. (Although this is possible with the addition of custom phases.)

More Strict Input Value Parsing

Absinthe now more closely adheres to the GraphQL specification's rules about input value coercion, to include:

  • Int: Disallowing automatic coercion of, eg, "1" to 1
  • String: Disallowing automatic coercion of, eg, 1 to "1"
  • Enum: Disallowing quoted values, eg, "RED" vs RED

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.

Validation Errors Prevent Resolution

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.)

No AST Nodes in Resolution

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).

List Coercion

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{}]}.

Simpler Adapters

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.

Mix Task Removal

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.

Other Changes

Resolution Functions

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

Resolution Plugins (+ Async & Batching)

v1.2 features a Resolution Plugin mechanism. See the docs in the Absinthe.Resolution.Plugin module for more information.

Resolution Info

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.

Custom Type Metadata

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.

Mix Tasks

  • 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 for absinthe.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:

Enum values

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"


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.

Type Definitions

Here's an example of an object definition in the old notation style:

@absinthe :type
def car do
    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"}

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"}



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).

Type Modules

In the past, this is how you would import types from another module:

defmodule Types do
  use Absinthe.Type.Definitions

  # ...

defmodule Schema do
  use Absinthe.Schema, type_modules: [Types]

  # ...

This is how it is done now:

defmodule Types do
  use Absinthe.Schema.Notation

  # ...

defmodule Schema do
  use Absinthe.Schema

  import_types Types

  # ...

More Information

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:

Resolution Functions

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:


  values: %{
    "foo" => :f,
    "bar" => :b


  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.

Version History

Version Date
1.3.2 23 Jun 2017 15:06
1.3.1 09 Jun 2017 19:06
1.3.0 25 Apr 2017 11:04
1.3.0-rc.0 13 Apr 2017 00:04
1.3.0-beta.2 27 Mar 2017 23:03
1.3.0-beta.1 14 Mar 2017 03:03
1.3.0-beta.0 08 Mar 2017 02:03
1.2.6 10 Feb 2017 13:02
1.2.5 29 Jan 2017 01:01
1.2.4 27 Jan 2017 16:01
1.2.3 23 Dec 2016 17:12
1.2.2 23 Dec 2016 15:12
1.2.1 13 Nov 2016 22:11
1.2.0 03 Nov 2016 13:11
1.2.0-rc.0 30 Oct 2016 23:10
1.2.0-beta.0 15 Oct 2016 20:10
1.2.0-alpha.2 11 Oct 2016 12:10
1.1.11 30 Sep 2016 21:09
1.2.0-alpha.1 30 Sep 2016 17:09
1.2.0-alpha0 23 Sep 2016 03:09
1.1.10 02 Sep 2016 23:09
1.1.9 01 Sep 2016 15:09
1.1.8 26 Jul 2016 18:07
1.1.7 15 Jun 2016 06:06
1.1.6 30 Apr 2016 02:04
1.1.5 26 Apr 2016 18:04
1.1.4 25 Apr 2016 15:04
1.1.3 02 Apr 2016 20:04
1.1.2 22 Mar 2016 17:03
1.1.1 22 Mar 2016 02:03
1.1.0 19 Mar 2016 00:03
1.0.0 02 Mar 2016 03:03
0.5.2 01 Feb 2016 08:02
0.5.1 29 Jan 2016 09:01
0.5.0 29 Jan 2016 06:01
0.4.6 28 Jan 2016 22:01
0.4.5 27 Jan 2016 22:01
0.4.4 22 Jan 2016 01:01
0.4.3 18 Jan 2016 10:01
0.4.2 17 Jan 2016 10:01
0.4.1 15 Jan 2016 23:01
0.4.0 13 Jan 2016 18:01
0.2.3 04 Jan 2016 06:01
0.2.2 30 Dec 2015 06:12
0.2.1 30 Dec 2015 04:12
0.1.0 29 Dec 2015 08:12