Skip to content

Commit 7a889c6

Browse files
authored
Merge branch 'master' into raise-informative-error-on-batched-resolver-timeout
2 parents f8450e1 + 9155d1a commit 7a889c6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+1295
-212
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,18 @@
22

33
## Unreleased
44

5+
- Bug Fix: Adds **optional fix** for non compliant built-in scalar Int type. `use Absinthe.Schema, use_spec_compliant_int_scalar: true` in your schema to use the fixed Int type. It is also advisable to upgrade for custom types if you are leveraging the use of integers outside the GraphQl standard. [#1131](https://github.com/absinthe-graphql/absinthe/pull/1131).
6+
- Feature: [Support error tuples when scalar parsing fails](https://github.com/absinthe-graphql/absinthe/pull/1187)
57
- Feature: [Convert SDL Language.\* structs to SDL notation](https://github.com/absinthe-graphql/absinthe/pull/1160)
68
- Feature: [Add support for type extensions](https://github.com/absinthe-graphql/absinthe/pull/1157)
9+
- Bug Fix: [Add type system directives to introspection results](https://github.com/absinthe-graphql/absinthe/pull/1189)
710
- Bug Fix: [Add `__private__` field to EnumValueDefinition](https://github.com/absinthe-graphql/absinthe/pull/1148)
811
- Bug Fix: [Fix bug in Schema.**absinthe_types**(:all) for Persistent Term](https://github.com/absinthe-graphql/absinthe/pull/1161)
12+
- Bug Fix: [Fix default enum value check for SDL schema's](https://github.com/absinthe-graphql/absinthe/pull/1188)
913
- Feature: [Add `import_directives` macro](https://github.com/absinthe-graphql/absinthe/pull/1158)
1014
- BugFix: [Improved error when batches fail timeouts](https://github.com/absinthe-graphql/absinthe/pull/1180)
15+
- Feature: [Support type extensions on schema declarations](https://github.com/absinthe-graphql/absinthe/pull/1176)
16+
- Bug Fix: [Root objects are marked as referenced correctly](https://github.com/absinthe-graphql/absinthe/pull/1186)
1117

1218
## 1.7.0
1319

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
88
[![Last Updated](https://img.shields.io/github/last-commit/absinthe-graphql/absinthe.svg)](https://github.com/absinthe-graphql/absinthe/commits/master)
99

10-
[GraphQL](https://facebook.github.io/graphql/) implementation for Elixir.
10+
[GraphQL](https://github.com/graphql-elixir/graphql) implementation for Elixir.
1111

1212
Goals:
1313

@@ -61,7 +61,7 @@ We care about support for third-party frameworks, both on the back and
6161
front end.
6262

6363
So far, we include specialized support for Phoenix and Plug on the backend,
64-
and [Relay](https://facebook.github.io/relay/) on the frontend.
64+
and [Relay](https://relay.dev/) on the frontend.
6565

6666
Of course we work out of the box with other frontend frameworks and GraphQL
6767
clients, too.

guides/custom-scalars.md

+5-6
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ providing `parse` and `serialize` functions.
1515

1616
Here's the definition for `:datetime` from `Absinthe.Type.Custom`:
1717

18-
``` elixir
18+
```elixir
1919
@desc """
2020
The `DateTime` scalar type represents a date and time in the UTC
2121
timezone. The DateTime appears in a JSON response as an ISO8601 formatted
@@ -68,7 +68,7 @@ mutation CreatePost {
6868

6969
If our schema defines a `:published_at` argument with the `:datetime` type:
7070

71-
``` elixir
71+
```elixir
7272
field :post, :post do
7373
arg :published_at, :datetime
7474
resolve fn _, args, _ ->
@@ -90,10 +90,9 @@ correct result. That result will be used as the value of the
9090
`:published_at` argument when it's passed to the `:post` field
9191
resolver.
9292

93-
> It's important to note that---currently---the correct result from a
94-
> scalar's `parse` function in the event of the error is a lone atom,
95-
> `:error`, not an error tuple with a reason. In a future version of
96-
> Absinthe, custom parse errors may be supported.
93+
In the event of an error, the parse function can return either a lone
94+
atom `:error` or error tuple e.g. `{:error, "Reason of error"}`. The
95+
reason will be included in the output of the executed GraphQL document.
9796

9897
The serializer of `:datetime` is a pretty simple affair; it uses the
9998
`DateTime.to_iso8601/1` utility function. It would be called to

guides/introduction/overview.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Overview
22

3-
Absinthe is the GraphQL toolkit for Elixir, an implementation of the [GraphQL specification](https://facebook.github.io/graphql/) built to suit the language's capabilities and idiomatic style.
3+
Absinthe is the GraphQL toolkit for Elixir, an implementation of the [GraphQL specification](https://github.com/graphql-elixir/graphql) built to suit the language's capabilities and idiomatic style.
44

55
The Absinthe project consists of several complementary packages. You can find the full listing on the [absinthe-graphql](https://github.com/absinthe-graphql) GitHub organization page.
66

guides/introspection.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Schema Introspection
22

33
You can introspect your schema using `__schema`, `__type`, and `__typename`,
4-
as [described in the specification](https://facebook.github.io/graphql/#sec-Introspection).
4+
as [described in the specification](https://spec.graphql.org/October2021/#sec-Introspection).
55

66
### Examples
77

@@ -89,7 +89,7 @@ Getting the name of the fields for a named type:
8989
```
9090

9191
Note that you may have to nest several depths of `type`/`ofType`, as
92-
type information includes any wrapping layers of [List](https://facebook.github.io/graphql/#sec-List) and/or [NonNull](https://facebook.github.io/graphql/#sec-Non-null).
92+
type information includes any wrapping layers of [List](https://spec.graphql.org/October2021/#sec-List) and/or [NonNull](https://spec.graphql.org/October2021/#sec-Non-Null).
9393

9494
## Using GraphiQL
9595

guides/tutorial/our-first-query.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ end
4343
> custom type name as a `:name` option to the `object` macro.
4444
4545
If you're curious what the type `:id` is used by the `:id` field, see
46-
the [GraphQL spec](https://facebook.github.io/graphql/#sec-ID). It's
46+
the [GraphQL spec](https://spec.graphql.org/October2021/#sec-ID). It's
4747
an opaque value, and in our case is just the regular Ecto id, but
4848
serialized as a string.
4949

guides/variables.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
GraphQL supports query documents that declare variables that can be accepted to fill-in values. This is a useful mechanism for reusing GraphQL documents---instead of attempting to interpolate values yourself.
44

5-
- To support variables, simply define them for your query document [as the specification expects](https://facebook.github.io/graphql/#sec-Language.Query-Document.Variables), and pass in a `variables` option to `Absinthe.run`.
5+
- To support variables, simply define them for your query document [as the specification expects](https://spec.graphql.org/October2021/#sec-Language.Variables), and pass in a `variables` option to `Absinthe.run`.
66
- If you're using [absinthe_plug](https://github.com/absinthe-graphql/absinthe_plug), variables are passed in for you automatically after being parsed
77
from the query parameters or `POST` body.
88

lib/absinthe/blueprint/schema.ex

+22-1
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ defmodule Absinthe.Blueprint.Schema do
117117
Schema.InterfaceTypeDefinition,
118118
Schema.UnionTypeDefinition,
119119
Schema.EnumValueDefinition,
120-
Schema.TypeExtensionDefinition
120+
Schema.TypeExtensionDefinition,
121+
Schema.SchemaDeclaration
121122
]
122123

123124
defp build_types([%module{} = type | rest], stack, buff) when module in @simple_open do
@@ -196,6 +197,7 @@ defmodule Absinthe.Blueprint.Schema do
196197
Schema.InterfaceTypeDefinition,
197198
Schema.ObjectTypeDefinition,
198199
Schema.ScalarTypeDefinition,
200+
Schema.SchemaDeclaration,
199201
Schema.UnionTypeDefinition
200202
]
201203
defp build_types(
@@ -210,6 +212,14 @@ defmodule Absinthe.Blueprint.Schema do
210212
build_types(rest, [%{extend | definition: def} | stack], buff)
211213
end
212214

215+
defp build_types(
216+
[:close | rest],
217+
[%Schema.FieldDefinition{} = field, %Schema.SchemaDeclaration{} = declaration | stack],
218+
buff
219+
) do
220+
build_types(rest, [push(declaration, :field_definitions, field) | stack], buff)
221+
end
222+
213223
defp build_types([:close | rest], [%Schema.FieldDefinition{} = field, obj | stack], buff) do
214224
field =
215225
field
@@ -271,6 +281,17 @@ defmodule Absinthe.Blueprint.Schema do
271281
build_types(rest, [schema | stack], buff)
272282
end
273283

284+
defp build_types(
285+
[:close | rest],
286+
[%Schema.SchemaDeclaration{} = schema_declaration, schema | stack],
287+
buff
288+
) do
289+
# The declaration is pushed into the :type_definitions instead of the :schema_declaration
290+
# as it will be split off later in the ApplyDeclaration phase
291+
schema = push(schema, :type_definitions, schema_declaration)
292+
build_types(rest, [schema | stack], buff)
293+
end
294+
274295
defp build_types([:close | rest], [%Schema.SchemaDefinition{} = schema, bp], buff) do
275296
bp = push(bp, :schema_definitions, schema)
276297
build_types(rest, [bp], buff)

lib/absinthe/blueprint/transform.ex

+3-1
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,13 @@ defmodule Absinthe.Blueprint.Transform do
8686
Blueprint.Schema.InterfaceTypeDefinition => [:interfaces, :fields, :directives],
8787
Blueprint.Schema.ObjectTypeDefinition => [:interfaces, :fields, :directives],
8888
Blueprint.Schema.ScalarTypeDefinition => [:directives],
89+
Blueprint.Schema.SchemaDeclaration => [:directives, :field_definitions],
8990
Blueprint.Schema.SchemaDefinition => [
9091
:directive_definitions,
9192
:type_definitions,
9293
:type_extensions,
93-
:directives
94+
:directives,
95+
:schema_declaration
9496
],
9597
Blueprint.Schema.TypeExtensionDefinition => [:definition],
9698
Blueprint.Schema.UnionTypeDefinition => [:directives, :types]

lib/absinthe/formatter.ex

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ defmodule Absinthe.Formatter do
2020
# Define the desired plugins
2121
plugins: [Absinthe.Formatter],
2222
# Remember to update the inputs list to include the new extensions
23-
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}", "{lib, priv}/**/*.{gql,graphql}"]
23+
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}", "{lib,priv}/**/*.{gql,graphql}"]
2424
]
2525
```
2626
"""

lib/absinthe/introspection.ex

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ defmodule Absinthe.Introspection do
33
Introspection support.
44
55
You can introspect your schema using `__schema`, `__type`, and `__typename`,
6-
as [described in the specification](https://facebook.github.io/graphql/#sec-Introspection).
6+
as [described in the specification](https://spec.graphql.org/October2021/#sec-Introspection).
77
88
## Examples
99
@@ -94,8 +94,8 @@ defmodule Absinthe.Introspection do
9494
```
9595
9696
(Note that you may have to nest several depths of `type`/`ofType`, as
97-
type information includes any wrapping layers of [List](https://facebook.github.io/graphql/#sec-List)
98-
and/or [NonNull](https://facebook.github.io/graphql/#sec-Non-null).)
97+
type information includes any wrapping layers of [List](https://spec.graphql.org/October2021/#sec-List)
98+
and/or [NonNull](https://spec.graphql.org/October2021/#sec-Non-Null).)
9999
"""
100100

101101
alias Absinthe.Type

lib/absinthe/phase.ex

+9-2
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,24 @@ defmodule Absinthe.Phase do
2525
@behaviour Phase
2626
import(unquote(__MODULE__))
2727

28-
@spec flag_invalid(Blueprint.node_t()) :: Blueprint.node_t()
28+
@spec flag_invalid(node :: Blueprint.node_t()) :: Blueprint.node_t()
2929
def flag_invalid(%{flags: _} = node) do
3030
Absinthe.Blueprint.put_flag(node, :invalid, __MODULE__)
3131
end
3232

33-
@spec flag_invalid(Blueprint.node_t(), atom) :: Blueprint.node_t()
33+
@spec flag_invalid(node :: Blueprint.node_t(), flag :: atom) :: Blueprint.node_t()
3434
def flag_invalid(%{flags: _} = node, flag) do
3535
flagging = %{:invalid => __MODULE__, flag => __MODULE__}
3636
update_in(node.flags, &Map.merge(&1, flagging))
3737
end
3838

39+
@spec flag_invalid(node :: Blueprint.node_t(), flag :: atom, reason :: String.t()) ::
40+
Blueprint.node_t()
41+
def flag_invalid(%{flags: _} = node, flag, reason) do
42+
flagging = %{:invalid => {__MODULE__, reason}, flag => __MODULE__}
43+
update_in(node.flags, &Map.merge(&1, flagging))
44+
end
45+
3946
def put_flag(%{flags: _} = node, flag) do
4047
Absinthe.Blueprint.put_flag(node, flag, __MODULE__)
4148
end

lib/absinthe/phase/document/arguments/parse.ex

+10
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ defmodule Absinthe.Phase.Document.Arguments.Parse do
2626

2727
{:error, flag} ->
2828
%{node | normalized: normalized |> flag_invalid(flag)}
29+
30+
{:error, flag, reason} ->
31+
normalized = normalized |> flag_invalid(flag, reason)
32+
%{node | normalized: normalized}
2933
end
3034
end
3135

@@ -41,6 +45,9 @@ defmodule Absinthe.Phase.Document.Arguments.Parse do
4145
:error ->
4246
{:error, :bad_parse}
4347

48+
{:error, reason} ->
49+
{:error, :bad_parse, reason}
50+
4451
{:ok, val} ->
4552
{:ok, val}
4653
end
@@ -55,6 +62,9 @@ defmodule Absinthe.Phase.Document.Arguments.Parse do
5562
:error ->
5663
{:error, :bad_parse}
5764

65+
{:error, reason} ->
66+
{:error, :bad_parse, reason}
67+
5868
{:ok, val} ->
5969
{:ok, val}
6070
end

lib/absinthe/phase/document/validation/arguments_of_correct_type.ex

+37-9
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ defmodule Absinthe.Phase.Document.Validation.ArgumentsOfCorrectType do
5858
{%{schema_node: nil} = child, _} ->
5959
collect_child_errors(child, schema)
6060

61-
{%{flags: %{invalid: _}} = child, idx} ->
61+
{%{flags: %{invalid: invalid_flag}} = child, idx} ->
6262
child_type_name =
6363
child.schema_node
6464
|> Type.value_type(schema)
@@ -67,7 +67,12 @@ defmodule Absinthe.Phase.Document.Validation.ArgumentsOfCorrectType do
6767
child_inspected_value = Blueprint.Input.inspect(child)
6868

6969
[
70-
value_error_message(idx, child_type_name, child_inspected_value)
70+
value_error_message(
71+
idx,
72+
child_type_name,
73+
child_inspected_value,
74+
custom_error(invalid_flag)
75+
)
7176
| collect_child_errors(child, schema)
7277
]
7378

@@ -90,7 +95,7 @@ defmodule Absinthe.Phase.Document.Validation.ArgumentsOfCorrectType do
9095

9196
[unknown_field_error_message(child.name, field_suggestions)]
9297

93-
%{flags: %{invalid: _}} = child ->
98+
%{flags: %{invalid: invalid_flag}} = child ->
9499
child_type_name =
95100
Type.value_type(child.schema_node, schema)
96101
|> Type.name(schema)
@@ -105,7 +110,12 @@ defmodule Absinthe.Phase.Document.Validation.ArgumentsOfCorrectType do
105110
child_inspected_value = Blueprint.Input.inspect(child.input_value)
106111

107112
[
108-
value_error_message(child.name, child_type_name, child_inspected_value)
113+
value_error_message(
114+
child.name,
115+
child_type_name,
116+
child_inspected_value,
117+
custom_error(invalid_flag)
118+
)
109119
| child_errors
110120
]
111121

@@ -114,6 +124,13 @@ defmodule Absinthe.Phase.Document.Validation.ArgumentsOfCorrectType do
114124
end)
115125
end
116126

127+
defp collect_child_errors(
128+
%Blueprint.Input.Value{normalized: %{flags: %{invalid: {_, reason}}} = norm},
129+
schema
130+
) do
131+
[reason | collect_child_errors(norm, schema)]
132+
end
133+
117134
defp collect_child_errors(%Blueprint.Input.Value{normalized: norm}, schema) do
118135
collect_child_errors(norm, schema)
119136
end
@@ -149,13 +166,17 @@ defmodule Absinthe.Phase.Document.Validation.ArgumentsOfCorrectType do
149166
error_message(arg_name, inspected_value) <> "\n" <> Enum.join(verbose_errors, "\n")
150167
end
151168

152-
def value_error_message(id, expected_type_name, inspected_value) when is_integer(id) do
169+
def value_error_message(id, expected_type_name, inspected_value, custom_error \\ nil)
170+
171+
def value_error_message(id, expected_type_name, inspected_value, custom_error)
172+
when is_integer(id) do
153173
~s(In element ##{id + 1}: ) <>
154-
expected_type_error_message(expected_type_name, inspected_value)
174+
expected_type_error_message(expected_type_name, inspected_value, custom_error)
155175
end
156176

157-
def value_error_message(id, expected_type_name, inspected_value) do
158-
~s(In field "#{id}": ) <> expected_type_error_message(expected_type_name, inspected_value)
177+
def value_error_message(id, expected_type_name, inspected_value, custom_error) do
178+
~s(In field "#{id}": ) <>
179+
expected_type_error_message(expected_type_name, inspected_value, custom_error)
159180
end
160181

161182
def unknown_field_error_message(field_name, suggestions \\ [])
@@ -169,7 +190,14 @@ defmodule Absinthe.Phase.Document.Validation.ArgumentsOfCorrectType do
169190
Utils.MessageSuggestions.suggest_message(suggestions)
170191
end
171192

172-
defp expected_type_error_message(expected_type_name, inspected_value) do
193+
defp expected_type_error_message(expected_type_name, inspected_value, nil) do
173194
~s(Expected type "#{expected_type_name}", found #{inspected_value}.)
174195
end
196+
197+
defp expected_type_error_message(expected_type_name, inspected_value, custom_error) do
198+
~s(Expected type "#{expected_type_name}", found #{inspected_value}.\n#{custom_error})
199+
end
200+
201+
defp custom_error({_, reason}), do: reason
202+
defp custom_error(_), do: nil
175203
end

0 commit comments

Comments
 (0)