Packages
ash_graphql
1.9.2
1.10.0
1.9.4
1.9.3
1.9.2
1.9.1
1.9.0
1.8.5
1.8.4
1.8.3
1.8.2
1.8.1
1.8.0
1.7.17
1.7.16
1.7.15
1.7.14
1.7.13
1.7.12
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.0
1.5.1
1.5.0
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.3.4
1.3.3
1.3.2
1.3.1
1.3.0
1.2.1
1.2.0
1.1.1
1.1.0
1.0.1
1.0.0
1.0.0-rc.5
1.0.0-rc.4
retired
1.0.0-rc.3
1.0.0-rc.2
1.0.0-rc.1
1.0.0-rc.0
0.28.1
0.28.0
0.27.1
0.27.0
0.26.9
0.26.8
0.26.7
0.26.6
0.26.5
0.26.4
0.26.3
0.26.2
0.26.0
0.25.13
0.25.12
0.25.10
0.25.9
0.25.8
0.25.7
0.25.6
0.25.5
0.25.4
0.25.3
0.25.2
0.25.1
0.25.0
0.24.1
0.24.0
0.23.3
0.23.2
0.23.1
0.23.0
0.22.13
0.22.12
0.22.11
0.22.10
0.22.9
0.22.8
0.22.7
0.22.6
0.22.4
0.22.3
0.22.2
0.22.1
0.22.0
0.21.0
retired
0.20.5
0.20.4
0.20.3
0.20.2
0.20.1
0.20.0-rc.3
0.20.0-rc.2
0.20.0-rc.1
0.20.0-rc.0
0.19.0
0.18.0-rc0
0.17.5
0.17.5-rc0
0.17.4
0.17.2
0.17.1
0.17.0
0.16.28
0.16.27
0.16.26
0.16.25
0.16.24
0.16.23
0.16.22
0.16.21
0.16.20
0.16.18-rc5
0.16.18-rc4
0.16.18-rc3
0.16.18-rc2
0.16.18-rc1
0.16.18-rc0
0.16.17
0.16.16
0.16.15
0.16.14
0.16.13
0.16.12
0.16.11
0.16.10
0.16.9
0.16.8
0.16.7
0.16.6
0.16.5
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.10
0.15.9
0.15.8
0.15.7
0.15.6
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.1
0.14.0
0.13.1
0.13.0
0.12.5
0.12.4
0.12.3
0.12.1
0.12.0
0.10.0
0.9.5
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.0
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.3
0.6.2
0.6.1
0.6.0
0.5.0
0.4.0
0.3.2
0.3.1
0.3.0
0.2.1
0.2.0
0.1.3
0.1.2
The extension for building GraphQL APIs with Ash
Current section
Files
Jump to
Current section
Files
lib/graphql/phase/inject_metadata.ex
# SPDX-FileCopyrightText: 2020 ash_graphql contributors <https://github.com/ash-project/ash_graphql/graphs.contributors>
#
# SPDX-License-Identifier: MIT
defmodule AshGraphql.Phase.InjectMetadata do
@moduledoc """
Absinthe phase that injects metadata into response extensions.
The key under which metadata appears is configured via the `response_metadata` option.
Automatically added to the pipeline by `AshGraphql.Plugin.ResponseMetadata`
when `response_metadata` is enabled.
"""
use Absinthe.Phase
require Logger
@doc false
def run(blueprint, options) do
schema = Keyword.fetch!(options, :schema)
response_metadata_config = schema.response_metadata()
if response_metadata_config do
blueprint = inject_metadata(blueprint, response_metadata_config)
{:ok, blueprint}
else
{:ok, blueprint}
end
end
defp inject_metadata(blueprint, response_metadata_config) do
acc = blueprint.execution.acc[:ash_graphql] || %{}
start_time = acc[:start_time]
end_time = acc[:end_time]
duration_ms =
if start_time && end_time do
System.convert_time_unit(end_time - start_time, :native, :millisecond)
else
if is_nil(start_time) do
Logger.warning(
"AshGraphql response_metadata: start_time not found. " <>
"Ensure AshGraphql.Plugin.ResponseMetadata is included in your schema's plugins/0 function."
)
end
nil
end
operation = Enum.find(blueprint.operations, & &1.current)
complexity =
case operation do
%{complexity: c} when is_integer(c) -> c
_ -> nil
end
operation_name =
case operation do
%{name: name} when not is_nil(name) -> name
_ -> nil
end
operation_type =
case operation do
%{type: t} -> t
_ -> nil
end
info = %{
complexity: complexity,
duration_ms: duration_ms,
operation_name: operation_name,
operation_type: operation_type
}
{key, metadata} = build_metadata(response_metadata_config, info)
if is_map(metadata) && map_size(metadata) > 0 do
update_in(blueprint.result, fn result ->
result = result || %{}
extensions = Map.get(result, :extensions, %{})
existing = Map.get(extensions, key, %{})
merged = Map.merge(existing, metadata)
extensions = Map.put(extensions, key, merged)
Map.put(result, :extensions, extensions)
end)
else
blueprint
end
end
defp build_metadata(true, _info) do
Logger.warning(
"AshGraphql response_metadata is set to `true` but requires a key. " <>
"Use `response_metadata: :my_extension_key` to specify the extensions key."
)
{nil, nil}
end
defp build_metadata(key, info) when is_atom(key) do
{key, AshGraphql.DefaultMetadataHandler.build_metadata(info)}
end
defp build_metadata({key, {module, function, args}}, info)
when is_atom(key) and is_atom(module) and is_atom(function) and is_list(args) do
result = apply(module, function, [info | args])
case result do
map when is_map(map) ->
{key, map}
nil ->
{key, nil}
other ->
Logger.warning(
"AshGraphql response_metadata handler #{inspect(module)}.#{function}/#{length(args) + 1} " <>
"returned #{inspect(other)}, expected a map or nil. Metadata will not be included."
)
{key, nil}
end
rescue
e ->
Logger.warning(
"AshGraphql response_metadata handler #{inspect(module)}.#{function}/#{length(args) + 1} " <>
"raised: #{Exception.format(:error, e, __STACKTRACE__)}. Metadata will not be included."
)
{key, nil}
catch
:throw, value ->
Logger.warning(
"AshGraphql response_metadata handler #{inspect(module)}.#{function}/#{length(args) + 1} " <>
"threw: #{inspect(value)}. Metadata will not be included."
)
{key, nil}
:exit, reason ->
Logger.warning(
"AshGraphql response_metadata handler #{inspect(module)}.#{function}/#{length(args) + 1} " <>
"exited: #{inspect(reason)}. Metadata will not be included."
)
{key, nil}
end
defp build_metadata(false, _info), do: {nil, nil}
defp build_metadata(nil, _info), do: {nil, nil}
defp build_metadata(invalid_config, _info) do
Logger.warning(
"AshGraphql response_metadata received invalid configuration: #{inspect(invalid_config)}. " <>
"Expected an atom key, `false`, or `{key, {Module, :function, args}}` tuple. Metadata will not be included."
)
{nil, nil}
end
end