Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose type system directives in introspection #1189

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

- Feature: [Convert SDL Language.\* structs to SDL notation](https://github.com/absinthe-graphql/absinthe/pull/1160)
- Feature: [Add support for type extensions](https://github.com/absinthe-graphql/absinthe/pull/1157)
- Bug Fix: [Add type system directives to introspection results](https://github.com/absinthe-graphql/absinthe/pull/1189)
- Bug Fix: [Add `__private__` field to EnumValueDefinition](https://github.com/absinthe-graphql/absinthe/pull/1148)
- Bug Fix: [Fix bug in Schema.**absinthe_types**(:all) for Persistent Term](https://github.com/absinthe-graphql/absinthe/pull/1161)
- Feature: [Add `import_directives` macro](https://github.com/absinthe-graphql/absinthe/pull/1158)
Expand Down
8 changes: 6 additions & 2 deletions lib/absinthe/phase/schema/build.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ defmodule Absinthe.Phase.Schema.Build do
%{schema_definitions: [schema]} = blueprint

types = build_types(blueprint)
directives = build_directives(blueprint)
directive_artifacts = build_directives(blueprint)

schema = %{schema | type_artifacts: types, directive_artifacts: directives}
schema = %{
schema
| type_artifacts: types,
directive_artifacts: schema.directive_artifacts ++ directive_artifacts
}

blueprint = %{blueprint | schema_definitions: [schema]}

Expand Down
2 changes: 1 addition & 1 deletion lib/absinthe/phase/schema/compile.ex
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ defmodule Absinthe.Phase.Schema.Compile do
do: {type_def.identifier, type_def.name}

directive_list =
Map.new(schema.directive_definitions, fn type_def ->
Map.new(schema.directive_artifacts, fn type_def ->
{type_def.identifier, type_def.name}
end)

Expand Down
26 changes: 26 additions & 0 deletions lib/absinthe/phase/schema/import_prototype_directives.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
defmodule Absinthe.Phase.Schema.ImportPrototypeDirectives do
@moduledoc false

# Imports directives from the prototype schema into the current schema.
# This ensures the type system directives such as `deprecated` are available
# for introspection as per the spec.
#
# Note that this does import the (type system) directives themselves, this
# is already done in an earlier phase.

@behaviour Absinthe.Phase
alias Absinthe.Blueprint

@spec run(Blueprint.t(), Keyword.t()) :: {:ok, Blueprint.t()}
def run(blueprint, _options \\ []) do
prototype_directives = Absinthe.Schema.directives(blueprint.prototype_schema)

%{schema_definitions: [schema]} = blueprint

schema = %{schema | directive_artifacts: prototype_directives}

blueprint = %{blueprint | schema_definitions: [schema]}

{:ok, blueprint}
end
end
2 changes: 1 addition & 1 deletion lib/absinthe/phase/schema/populate_persistent_term.ex
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ if Code.ensure_loaded?(:persistent_term) do
do: {type_def.identifier, type_def.name}

directive_list =
Map.new(schema.directive_definitions, fn type_def ->
Map.new(schema.directive_artifacts, fn type_def ->
{type_def.identifier, type_def.name}
end)

Expand Down
1 change: 1 addition & 0 deletions lib/absinthe/pipeline.ex
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ defmodule Absinthe.Pipeline do
Phase.Schema.ReformatDescriptions,
# This phase is run again now after additional validations
{Phase.Schema.Validation.Result, pass: :final},
Phase.Schema.ImportPrototypeDirectives,
Phase.Schema.Build,
Phase.Schema.InlineFunctions,
{Phase.Schema.Compile, options}
Expand Down
2 changes: 2 additions & 0 deletions lib/absinthe/schema/prototype/notation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ defmodule Absinthe.Schema.Prototype.Notation do
@pipeline_modifier __MODULE__

directive :deprecated do
description "Marks an element of a GraphQL schema as no longer supported."
arg :reason, :string

on [
Expand All @@ -34,6 +35,7 @@ defmodule Absinthe.Schema.Prototype.Notation do
def pipeline(pipeline) do
pipeline
|> Absinthe.Pipeline.without(Absinthe.Phase.Schema.Validation.QueryTypeMustBeObject)
|> Absinthe.Pipeline.without(Absinthe.Phase.Schema.ImportPrototypeDirectives)
|> Absinthe.Pipeline.replace(
Absinthe.Phase.Schema.TypeExtensionImports,
{Absinthe.Phase.Schema.TypeExtensionImports, []}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,22 @@ defmodule Elixir.Absinthe.Integration.Execution.Introspection.DirectivesTest do
data: %{
"__schema" => %{
"directives" => [
%{
"args" => [
%{"name" => "reason", "type" => %{"kind" => "SCALAR", "ofType" => nil}}
],
"isRepeatable" => false,
"locations" => [
"ARGUMENT_DEFINITION",
"ENUM_VALUE",
"FIELD_DEFINITION",
"INPUT_FIELD_DEFINITION"
],
"name" => "deprecated",
"onField" => false,
"onFragment" => false,
"onOperation" => false
},
%{
"args" => [
%{
Expand Down
24 changes: 24 additions & 0 deletions test/absinthe/introspection_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,30 @@ defmodule Absinthe.IntrospectionTest do
data: %{
"__schema" => %{
"directives" => [
%{
"description" =>
"Marks an element of a GraphQL schema as no longer supported.",
"isRepeatable" => false,
"locations" => [
"ARGUMENT_DEFINITION",
"ENUM_VALUE",
"FIELD_DEFINITION",
"INPUT_FIELD_DEFINITION"
],
"name" => "deprecated",
"onField" => false,
"onFragment" => false,
"onOperation" => false
},
%{
"description" => nil,
"isRepeatable" => false,
"locations" => ["FIELD_DEFINITION"],
"name" => "external",
"onField" => false,
"onFragment" => false,
"onOperation" => false
},
%{
"description" =>
"Directs the executor to include this field or fragment only when the `if` argument is true.",
Expand Down
10 changes: 10 additions & 0 deletions test/support/fixtures/color_schema.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@ defmodule Absinthe.Fixtures.ColorSchema do
use Absinthe.Schema
use Absinthe.Fixture

defmodule WithTypeSystemDirective do
use Absinthe.Schema.Prototype

directive :external do
on [:field_definition]
end
end

@prototype_schema WithTypeSystemDirective

@names %{
r: "RED",
g: "GREEN",
Expand Down