Packages
absinthe
1.1.0
1.11.0
1.10.2
1.10.1
1.10.0
1.9.1
1.9.0
1.8.0
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.8
1.6.7
retired
1.6.6
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.6.0-rc.1
1.6.0-rc.0
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.5.0-rc.5
1.5.0-rc.4
1.5.0-rc.3
1.5.0-rc.2
1.5.0-rc.1
1.5.0-rc.0
1.5.0-beta.2
1.5.0-beta.1
1.5.0-beta.0
1.5.0-alpha.4
1.5.0-alpha.3
1.5.0-alpha.2
1.5.0-alpha.1
1.5.0-alpha.0
1.4.16
1.4.15
1.4.14
1.4.13
1.4.12
1.4.11
1.4.10
1.4.9
1.4.8
retired
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.4.0-rc.3
1.4.0-rc.2
1.4.0-rc.1
1.4.0-rc.0
1.4.0-beta.5
1.4.0-beta.4
1.4.0-beta.3
1.4.0-beta.2
1.4.0-beta.1
1.3.2
1.3.1
1.3.0
1.3.0-rc.0
1.3.0-beta.2
1.3.0-beta.1
1.3.0-beta.0
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.2.0-rc.0
1.2.0-beta.0
1.2.0-alpha0
1.2.0-alpha.2
1.2.0-alpha.1
1.1.11
1.1.10
1.1.9
1.1.8
1.1.7
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.0
0.5.2
0.5.1
0.5.0
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.2.3
0.2.2
0.2.1
0.1.0
GraphQL for Elixir
Current section
122 Versions
Jump to
Current section
122 Versions
Compare versions
43
files changed
+2849
additions
-3217
deletions
| @@ -24,16 +24,16 @@ Please see the website at [http://absinthe-graphql.org](http://absinthe-graphql. | |
| 24 24 | - Schema definition |
| 25 25 | - All types (eg, Object, Input Object, Enum, Union, Interface, Scalar) |
| 26 26 | - Circular type references |
| 27 | - - Support for [custom scalars](http://absinthe-graphql.org/guides/custom-scalars) |
| 27 | + - Support for [custom scalars](http://absinthe-graphql.org/guides/custom-scalars/) |
| 28 28 | - Support for custom directives |
| 29 | - - Field, argument, and enum value [deprecation](http://absinthe-graphql.org/guides/deprecation) |
| 29 | + - Field, argument, and enum value [deprecation](http://absinthe-graphql.org/guides/deprecation/) |
| 30 30 | - Compile-time schema validation |
| 31 | - - [Introspection](http://absinthe-graphql.org/guides/introspection), compatible with GraphiQL |
| 31 | + - [Introspection](http://absinthe-graphql.org/guides/introspection/), compatible with GraphiQL |
| 32 32 | - Query execution |
| 33 33 | - General |
| 34 34 | - Named fragments, inline fragments, and fragment spreads with type conditions |
| 35 35 | - `@skip` and `@include` directives |
| 36 | - - [Adapter](http://absinthe-graphql.org/guides/adapters) mechanism to support conversion between camelCase query documents |
| 36 | + - [Adapter](http://absinthe-graphql.org/guides/adapters/) mechanism to support conversion between camelCase query documents |
| 37 37 | and snake_cased schema definition. |
| 38 38 | |
| 39 39 | ## Installation |
| @@ -42,7 +42,7 @@ Install from [Hex.pm](https://hex.pm/packages/absinthe): | |
| 42 42 | |
| 43 43 | ```elixir |
| 44 44 | def deps do |
| 45 | - [{:absinthe, "~> 1.0.0"}] |
| 45 | + [{:absinthe, "~> 1.1.0"}] |
| 46 46 | end |
| 47 47 | ``` |
| 48 48 | |
| @@ -63,12 +63,12 @@ See [CHANGELOG](./CHANGELOG.md) for upgrade steps between versions. | |
| 63 63 | ## Documentation |
| 64 64 | |
| 65 65 | - For the tutorial, guides, and general information about Absinthe-related |
| 66 | - projects, see [http://absinthe-graphql.org](http://absithe-graphql.org). |
| 67 | - - Links to the API documentation are available in the [project list](https://absinthe-graphql.org/projects). |
| 66 | + projects, see [http://absinthe-graphql.org](http://absinthe-graphql.org). |
| 67 | + - Links to the API documentation are available in the [project list](http://absinthe-graphql.org/projects/). |
| 68 68 | |
| 69 69 | ### Roadmap |
| 70 70 | |
| 71 | - See the Roadmap on [absinthe-graphql.org](https://absinthe-graphql.org/roadmap). |
| 71 | + See the Roadmap on [absinthe-graphql.org](http://absinthe-graphql.org/roadmap/). |
| 72 72 | |
| 73 73 | ## Related Projects |
| 74 74 | |
| @@ -81,7 +81,7 @@ BSD License | |
| 81 81 | Copyright (c) CargoSense, Inc. |
| 82 82 | |
| 83 83 | Parser derived from GraphQL Elixir, Copyright (c) Josh Price |
| 84 | - https://github.com/joshprice/graphql-elixir |
| 84 | + https://github.com/graphql-elixir/graphql-elixir |
| 85 85 | |
| 86 86 | Redistribution and use in source and binary forms, with or without modification, |
| 87 87 | are permitted provided that the following conditions are met: |
| @@ -8,9 +8,11 @@ | |
| 8 8 | <<"lib/absinthe/adapter/passthrough.ex">>,<<"lib/absinthe/execution.ex">>, |
| 9 9 | <<"lib/absinthe/execution/arguments.ex">>, |
| 10 10 | <<"lib/absinthe/execution/directives.ex">>, |
| 11 | - <<"lib/absinthe/execution/field.ex">>, |
| 11 | + <<"lib/absinthe/execution/field.ex">>,<<"lib/absinthe/execution/input.ex">>, |
| 12 | + <<"lib/absinthe/execution/input/meta.ex">>, |
| 12 13 | <<"lib/absinthe/execution/resolution.ex">>, |
| 13 14 | <<"lib/absinthe/execution/resolution/atom.ex">>, |
| 15 | + <<"lib/absinthe/execution/resolution/enum.ex">>, |
| 14 16 | <<"lib/absinthe/execution/resolution/field.ex">>, |
| 15 17 | <<"lib/absinthe/execution/resolution/interface.ex">>, |
| 16 18 | <<"lib/absinthe/execution/resolution/list.ex">>, |
| @@ -21,6 +23,7 @@ | |
| 21 23 | <<"lib/absinthe/execution/resolution/selection_set.ex">>, |
| 22 24 | <<"lib/absinthe/execution/resolution/union.ex">>, |
| 23 25 | <<"lib/absinthe/execution/runner.ex">>, |
| 26 | + <<"lib/absinthe/execution/variable.ex">>, |
| 24 27 | <<"lib/absinthe/execution/variables.ex">>,<<"lib/absinthe/fetch.ex">>, |
| 25 28 | <<"lib/absinthe/flag.ex">>,<<"lib/absinthe/introspection.ex">>, |
| 26 29 | <<"lib/absinthe/introspection/field.ex">>, |
| @@ -70,6 +73,7 @@ | |
| 70 73 | <<"lib/absinthe/schema/rule/object_must_implement_interfaces.ex">>, |
| 71 74 | <<"lib/absinthe/schema/rule/type_names_are_reserved.ex">>, |
| 72 75 | <<"lib/absinthe/schema/rule/type_names_are_unique.ex">>, |
| 76 | + <<"lib/absinthe/schema/rule/type_names_are_valid.ex">>, |
| 73 77 | <<"lib/absinthe/schema/verification.ex">>, |
| 74 78 | <<"lib/absinthe/schema/verification/unions.ex">>, |
| 75 79 | <<"lib/absinthe/traversal.ex">>,<<"lib/absinthe/traversal/node.ex">>, |
| @@ -86,14 +90,15 @@ | |
| 86 90 | <<"lib/absinthe/type/non_null.ex">>,<<"lib/absinthe/type/object.ex">>, |
| 87 91 | <<"lib/absinthe/type/reference.ex">>,<<"lib/absinthe/type/scalar.ex">>, |
| 88 92 | <<"lib/absinthe/type/union.ex">>,<<"lib/absinthe/utils.ex">>, |
| 93 | + <<"lib/absinthe/validation.ex">>, |
| 94 | + <<"lib/absinthe/validation/prevent_circular_fragments.ex">>, |
| 89 95 | <<"lib/absinthe/validation/required_input.ex">>, |
| 90 | - <<"src/absinthe_lexer.erl">>,<<"src/absinthe_lexer.xrl">>, |
| 91 | - <<"src/absinthe_parser.erl">>,<<"src/absinthe_parser.yrl">>, |
| 92 | - <<"src/ex_graphql_lexer.erl">>,<<"src/ex_graphql_parser.erl">>, |
| 93 | - <<"mix.exs">>,<<"README.md">>]}. |
| 96 | + <<"lib/mix/tasks/absinthe.schema.json.ex">>,<<"src/absinthe_lexer.erl">>, |
| 97 | + <<"src/absinthe_lexer.xrl">>,<<"src/absinthe_parser.erl">>, |
| 98 | + <<"src/absinthe_parser.yrl">>,<<"mix.exs">>,<<"README.md">>]}. |
| 94 99 | {<<"licenses">>,[<<"BSD">>]}. |
| 95 100 | {<<"links">>,[{<<"github">>,<<"https://github.com/CargoSense/absinthe">>}]}. |
| 96 | - {<<"maintainers">>,[<<"Bruce Williams">>]}. |
| 101 | + {<<"maintainers">>,[<<"Bruce Williams">>,<<"Ben Wilson">>]}. |
| 97 102 | {<<"name">>,<<"absinthe">>}. |
| 98 103 | {<<"requirements">>,[]}. |
| 99 | - {<<"version">>,<<"1.0.0">>}. |
| 104 | + {<<"version">>,<<"1.1.0">>}. |
| @@ -120,7 +120,7 @@ defmodule Absinthe do | |
| 120 120 | } |
| 121 121 | } |
| 122 122 | \""" |
| 123 | - |> Absinthe.run(App.Schema, variables: %{id: params[:item_id]}) |
| 123 | + |> Absinthe.run(App.Schema, variables: %{"id" => params[:item_id]}) |
| 124 124 | ``` |
| 125 125 | |
| 126 126 | The result, if `params[:item_id]` was `"foo"`, would be the same: |
| @@ -169,16 +169,22 @@ defmodule Absinthe do | |
| 169 169 | parse(%Absinthe.Language.Source{body: input}) |
| 170 170 | end |
| 171 171 | def parse(input) do |
| 172 | - case input.body |> tokenize do |
| 173 | - {:ok, []} -> {:ok, %Absinthe.Language.Document{}} |
| 174 | - {:ok, tokens} -> |
| 175 | - case :absinthe_parser.parse(tokens) do |
| 176 | - {:ok, _doc} = result -> |
| 177 | - result |
| 178 | - {:error, raw_error} -> |
| 179 | - {:error, format_raw_parse_error(raw_error)} |
| 180 | - end |
| 181 | - other -> other |
| 172 | + try do |
| 173 | + case input.body |> tokenize do |
| 174 | + {:ok, []} -> {:ok, %Absinthe.Language.Document{}} |
| 175 | + {:ok, tokens} -> |
| 176 | + |
| 177 | + case :absinthe_parser.parse(tokens) do |
| 178 | + {:ok, _doc} = result -> |
| 179 | + result |
| 180 | + {:error, raw_error} -> |
| 181 | + {:error, format_raw_parse_error(raw_error)} |
| 182 | + end |
| 183 | + other -> other |
| 184 | + end |
| 185 | + rescue |
| 186 | + error -> |
| 187 | + {:error, format_raw_parse_error(error)} |
| 182 188 | end |
| 183 189 | end |
| 184 190 | |
| @@ -220,7 +226,7 @@ defmodule Absinthe do | |
| 220 226 | } |
| 221 227 | } |
| 222 228 | \""" |
| 223 | - |> Absinthe.run(App.Schema, variables: %{id: params[:item_id]}) |
| 229 | + |> Absinthe.run(App.Schema, variables: %{"id" => params[:item_id]}) |
| 224 230 | ``` |
| 225 231 | |
| 226 232 | See the `Absinthe` module documentation for more examples. |
| @@ -229,11 +235,11 @@ defmodule Absinthe do | |
| 229 235 | def run(doc, schema, options \\ []) |
| 230 236 | @spec run(binary | Absinthe.Language.Source.t | Absinthe.Language.Document.t, Absinthe.Schema.t, Keyword.t) :: {:ok, Absinthe.Execution.result_t} | {:error, any} |
| 231 237 | def run(%Absinthe.Language.Document{} = document, schema, options) do |
| 232 | - case execute(schema, document, options) do |
| 233 | - {:ok, result} -> |
| 234 | - {:ok, result} |
| 235 | - other -> |
| 236 | - other |
| 238 | + case Absinthe.Validation.run(document) do |
| 239 | + {:ok, errors, doc} -> |
| 240 | + execute(schema, doc, errors, options) |
| 241 | + {:error, errors, _} -> |
| 242 | + {:ok, %{errors: errors}} |
| 237 243 | end |
| 238 244 | end |
| 239 245 | def run(input, schema, options) do |
| @@ -260,6 +266,16 @@ defmodule Absinthe do | |
| 260 266 | message = "#{problem}: #{field}" |
| 261 267 | %{message: message, locations: [%{line: line, column: 0}]} |
| 262 268 | end |
| 269 | + @unknown_error_msg "An unknown error occurred during parsing" |
| 270 | + @spec format_raw_parse_error(map) :: Execution.error_t |
| 271 | + defp format_raw_parse_error(%{} = error) do |
| 272 | + detail = if Exception.exception?(error) do |
| 273 | + ": " <> Exception.message(error) |
| 274 | + else |
| 275 | + "" |
| 276 | + end |
| 277 | + %{message: @unknown_error_msg <> detail} |
| 278 | + end |
| 263 279 | |
| 264 280 | @doc """ |
| 265 281 | Evaluates a query document against a schema, without options. |
| @@ -280,9 +296,9 @@ defmodule Absinthe do | |
| 280 296 | # EXECUTION |
| 281 297 | # |
| 282 298 | |
| 283 | - @spec execute(Absinthe.Schema.t, Absinthe.Language.Document.t, Keyword.t) :: Absinthe.Execution.result_t |
| 284 | - defp execute(schema, document, options) do |
| 285 | - %Absinthe.Execution{schema: schema, document: document} |
| 299 | + @spec execute(Absinthe.Schema.t, Absinthe.Language.Document.t, [], Keyword.t) :: Absinthe.Execution.result_t |
| 300 | + defp execute(schema, document, errors, options) do |
| 301 | + %Absinthe.Execution{schema: schema, document: document, errors: errors} |
| 286 302 | |> Absinthe.Execution.run(options) |
| 287 303 | end |
| @@ -62,21 +62,83 @@ defmodule Absinthe.Adapter do | |
| 62 62 | alias Absinthe.Execution |
| 63 63 | alias Absinthe.Language |
| 64 64 | |
| 65 | + def load_variables(variables) do |
| 66 | + variables |
| 67 | + |> map_var |
| 68 | + end |
| 69 | + |
| 70 | + defp do_load_variables(item) when is_map(item) do |
| 71 | + item |> map_var |
| 72 | + end |
| 73 | + defp do_load_variables(item) when is_list(item) do |
| 74 | + item |> list_var |
| 75 | + end |
| 76 | + defp do_load_variables(item) do |
| 77 | + item |
| 78 | + end |
| 79 | + |
| 80 | + defp list_var(items) do |
| 81 | + items |> list_var([]) |
| 82 | + end |
| 83 | + defp list_var([], acc), do: :lists.reverse(acc) |
| 84 | + defp list_var([item | rest], acc) do |
| 85 | + list_var(rest, [do_load_variables(item) | acc]) |
| 86 | + end |
| 87 | + |
| 88 | + defp map_var(items) do |
| 89 | + items |
| 90 | + |> Map.to_list |
| 91 | + |> map_var([]) |
| 92 | + end |
| 93 | + defp map_var([], acc), do: :maps.from_list(acc) |
| 94 | + defp map_var([{k, v} | rest], acc) do |
| 95 | + item = {to_internal_name(k, :key_name), do_load_variables(v)} |
| 96 | + map_var(rest, [item | acc]) |
| 97 | + end |
| 98 | + |
| 99 | + defp load_variable_definitions(%{variable: variable} = node) do |
| 100 | + %{ node | |
| 101 | + variable: Map.update!(variable, :name, &to_internal_name(&1, :variable)) |
| 102 | + } |
| 103 | + end |
| 104 | + |
| 65 105 | def load_document(%{definitions: definitions} = node) do |
| 66 106 | %{node | |
| 67 | - definitions: definitions |> Enum.map(&load_ast_node/1)} |
| 107 | + definitions: definitions |> Enum.map(&load_ast_node/1), |
| 108 | + } |
| 68 109 | end |
| 69 110 | |
| 70 111 | # Rename a AST node and traverse children |
| 112 | + defp load_ast_node(%Language.Directive{} = node) do |
| 113 | + %{node | |
| 114 | + arguments: Enum.map(node.arguments, &load_ast_node/1) |
| 115 | + } |
| 116 | + end |
| 117 | + defp load_ast_node(%Language.Variable{} = node) do |
| 118 | + %{node | name: to_internal_name(node.name, :variable)} |
| 119 | + end |
| 71 120 | defp load_ast_node(%Language.OperationDefinition{} = node) do |
| 72 121 | %{node | |
| 73 122 | name: node.name |> to_internal_name(:operation), |
| 74 | - selection_set: load_ast_node(node.selection_set)} |
| 123 | + selection_set: load_ast_node(node.selection_set), |
| 124 | + variable_definitions: node.variable_definitions |> Enum.map(&load_variable_definitions/1) |
| 125 | + } |
| 75 126 | end |
| 76 127 | defp load_ast_node(%Language.Fragment{} = node) do |
| 77 128 | %{node | |
| 129 | + directives: node.directives |> Enum.map(&load_ast_node/1), |
| 130 | + selection_set: load_ast_node(node.selection_set), |
| 131 | + } |
| 132 | + end |
| 133 | + defp load_ast_node(%Language.InlineFragment{} = node) do |
| 134 | + %{node | |
| 135 | + directives: node.directives |> Enum.map(&load_ast_node/1), |
| 78 136 | selection_set: load_ast_node(node.selection_set)} |
| 79 137 | end |
| 138 | + defp load_ast_node(%Language.FragmentSpread{} = node) do |
| 139 | + %{node | |
| 140 | + directives: node.directives |> Enum.map(&load_ast_node/1)} |
| 141 | + end |
| 80 142 | defp load_ast_node(%Language.SelectionSet{} = node) do |
| 81 143 | %{node | |
| 82 144 | selections: node.selections |> Enum.map(&load_ast_node/1)} |
| @@ -85,7 +147,9 @@ defmodule Absinthe.Adapter do | |
| 85 147 | %{node | |
| 86 148 | name: node.name |> to_internal_name(:field), |
| 87 149 | selection_set: load_ast_node(node.selection_set), |
| 88 | - arguments: node.arguments |> Enum.map(&load_ast_node/1)} |
| 150 | + arguments: node.arguments |> Enum.map(&load_ast_node/1), |
| 151 | + directives: node.directives |> Enum.map(&load_ast_node/1), |
| 152 | + } |
| 89 153 | end |
| 90 154 | defp load_ast_node(%Language.ObjectValue{} = node) do |
| 91 155 | %{node | |
| @@ -101,6 +165,9 @@ defmodule Absinthe.Adapter do | |
| 101 165 | name: node.name |> to_internal_name(:argument), |
| 102 166 | value: load_ast_node(node.value)} |
| 103 167 | end |
| 168 | + defp load_ast_node(%Language.ListValue{} = node) do |
| 169 | + %{node | values: Enum.map(node.values, &load_ast_node/1)} |
| 170 | + end |
| 104 171 | defp load_ast_node(other) do |
| 105 172 | other |
| 106 173 | end |
| @@ -151,10 +218,13 @@ defmodule Absinthe.Adapter do | |
| 151 218 | |> format_error(locations) |
| 152 219 | end |
| 153 220 | |
| 154 | - def format_error(%{value: value} = error_info) do |
| 221 | + def format_error(%{value: value} = error_info) when not is_function(value) do |
| 155 222 | %{error_info | value: inspect(value)} |
| 156 223 | |> format_error([]) |
| 157 224 | end |
| 225 | + def format_error(%{value: value} = error_info) do |
| 226 | + format_error(error_info, []) |
| 227 | + end |
| 158 228 | |
| 159 229 | defoverridable [load_document: 1, |
| 160 230 | dump_results: 1, |
| @@ -7,4 +7,8 @@ defmodule Absinthe.Adapter.Passthrough do | |
| 7 7 | |
| 8 8 | use Absinthe.Adapter |
| 9 9 | |
| 10 | + def load_document(doc), do: doc |
| 11 | + |
| 12 | + def dump_results(results), do: results |
| 13 | + |
| 10 14 | end |
Loading more files…