From ea9e806bd5fee90408fba1dd5d364fdd338e712e Mon Sep 17 00:00:00 2001 From: Fedor Ivanov Date: Tue, 1 Oct 2024 11:51:55 +0300 Subject: [PATCH] refactor: use middleware to check if GraphQL API is enabled (#10772) --- .../graphql/middleware/api_enabled.ex | 19 +++++++++ .../graphql/resolvers/address.ex | 25 ++++-------- .../graphql/resolvers/block.ex | 33 +++++++++------- .../graphql/resolvers/helper.ex | 9 ----- .../graphql/resolvers/internal_transaction.ex | 21 +++------- .../graphql/resolvers/token.ex | 13 +------ .../graphql/resolvers/token_transfer.ex | 37 ++++++------------ .../graphql/resolvers/transaction.ex | 39 +++++-------------- .../lib/block_scout_web/graphql/schema.ex | 10 ++++- apps/explorer/lib/explorer/graphql.ex | 17 +++++++- 10 files changed, 98 insertions(+), 125 deletions(-) create mode 100644 apps/block_scout_web/lib/block_scout_web/graphql/middleware/api_enabled.ex delete mode 100644 apps/block_scout_web/lib/block_scout_web/graphql/resolvers/helper.ex diff --git a/apps/block_scout_web/lib/block_scout_web/graphql/middleware/api_enabled.ex b/apps/block_scout_web/lib/block_scout_web/graphql/middleware/api_enabled.ex new file mode 100644 index 0000000000..dfe2bdb575 --- /dev/null +++ b/apps/block_scout_web/lib/block_scout_web/graphql/middleware/api_enabled.ex @@ -0,0 +1,19 @@ +defmodule BlockScoutWeb.GraphQL.Middleware.ApiEnabled do + @moduledoc """ + Middleware to check if the GraphQL API is enabled. + """ + alias Absinthe.Resolution + + @behaviour Absinthe.Middleware + + @api_is_disabled "GraphQL API is disabled." + + def call(resolution, _config) do + if resolution.context.api_enabled do + resolution + else + resolution + |> Resolution.put_result({:error, @api_is_disabled}) + end + end +end diff --git a/apps/block_scout_web/lib/block_scout_web/graphql/resolvers/address.ex b/apps/block_scout_web/lib/block_scout_web/graphql/resolvers/address.ex index 4a9449979b..1cbc324a10 100644 --- a/apps/block_scout_web/lib/block_scout_web/graphql/resolvers/address.ex +++ b/apps/block_scout_web/lib/block_scout_web/graphql/resolvers/address.ex @@ -1,28 +1,19 @@ defmodule BlockScoutWeb.GraphQL.Resolvers.Address do @moduledoc false - alias BlockScoutWeb.GraphQL.Resolvers.Helper alias Explorer.Chain - def get_by(_, %{hashes: hashes}, resolution) do - if resolution.context.api_enabled do - case Chain.hashes_to_addresses(hashes) do - [] -> {:error, "Addresses not found."} - result -> {:ok, result} - end - else - {:error, Helper.api_is_disabled()} + def get_by(_, %{hashes: hashes}, _) do + case Chain.hashes_to_addresses(hashes) do + [] -> {:error, "Addresses not found."} + result -> {:ok, result} end end - def get_by(_, %{hash: hash}, resolution) do - if resolution.context.api_enabled do - case Chain.hash_to_address(hash) do - {:error, :not_found} -> {:error, "Address not found."} - {:ok, _} = result -> result - end - else - {:error, Helper.api_is_disabled()} + def get_by(_, %{hash: hash}, _) do + case Chain.hash_to_address(hash) do + {:error, :not_found} -> {:error, "Address not found."} + {:ok, _} = result -> result end end end diff --git a/apps/block_scout_web/lib/block_scout_web/graphql/resolvers/block.ex b/apps/block_scout_web/lib/block_scout_web/graphql/resolvers/block.ex index 24de1e6259..1b03f48dfc 100644 --- a/apps/block_scout_web/lib/block_scout_web/graphql/resolvers/block.ex +++ b/apps/block_scout_web/lib/block_scout_web/graphql/resolvers/block.ex @@ -1,29 +1,32 @@ defmodule BlockScoutWeb.GraphQL.Resolvers.Block do @moduledoc false - alias BlockScoutWeb.GraphQL.Resolvers.Helper alias Explorer.Chain alias Explorer.Chain.Transaction @api_true [api?: true] - def get_by(_, %{number: number}, resolution) do - with {:api_enabled, true} <- {:api_enabled, resolution.context.api_enabled}, - {:ok, _} = result <- Chain.number_to_block(number, @api_true) do - result - else - {:api_enabled, false} -> {:error, Helper.api_is_disabled()} - {:error, :not_found} -> {:error, "Block number #{number} was not found."} + def get_by(_, %{number: number}, _) do + number + |> Chain.number_to_block(@api_true) + |> case do + {:ok, _} = result -> + result + + {:error, :not_found} -> + {:error, "Block number #{number} was not found."} end end - def get_by(%Transaction{block_hash: hash}, _, resolution) do - with {:api_enabled, true} <- {:api_enabled, resolution.context.api_enabled}, - {:ok, _} = result <- Chain.hash_to_block(hash, @api_true) do - result - else - {:api_enabled, false} -> {:error, Helper.api_is_disabled()} - {:error, :not_found} -> {:error, "Block hash #{to_string(hash)} was not found."} + def get_by(%Transaction{block_hash: hash}, _, _) do + hash + |> Chain.hash_to_block(@api_true) + |> case do + {:ok, _} = result -> + result + + {:error, :not_found} -> + {:error, "Block hash #{to_string(hash)} was not found."} end end end diff --git a/apps/block_scout_web/lib/block_scout_web/graphql/resolvers/helper.ex b/apps/block_scout_web/lib/block_scout_web/graphql/resolvers/helper.ex deleted file mode 100644 index 215e713acf..0000000000 --- a/apps/block_scout_web/lib/block_scout_web/graphql/resolvers/helper.ex +++ /dev/null @@ -1,9 +0,0 @@ -defmodule BlockScoutWeb.GraphQL.Resolvers.Helper do - @moduledoc """ - Helper functions for BlockScoutWeb.GraphQL.Resolvers modules - """ - - @api_is_disabled "GraphQL API is disabled." - - def api_is_disabled, do: @api_is_disabled -end diff --git a/apps/block_scout_web/lib/block_scout_web/graphql/resolvers/internal_transaction.ex b/apps/block_scout_web/lib/block_scout_web/graphql/resolvers/internal_transaction.ex index 647ae0b361..14e0093eef 100644 --- a/apps/block_scout_web/lib/block_scout_web/graphql/resolvers/internal_transaction.ex +++ b/apps/block_scout_web/lib/block_scout_web/graphql/resolvers/internal_transaction.ex @@ -2,26 +2,17 @@ defmodule BlockScoutWeb.GraphQL.Resolvers.InternalTransaction do @moduledoc false alias Absinthe.Relay.Connection - alias BlockScoutWeb.GraphQL.Resolvers.Helper alias Explorer.Chain.Transaction alias Explorer.{GraphQL, Repo} - def get_by(%{transaction_hash: _, index: _} = args, resolution) do - if resolution.context.api_enabled do - GraphQL.get_internal_transaction(args) - else - {:error, Helper.api_is_disabled()} - end + def get_by(%{transaction_hash: _, index: _} = args, _) do + GraphQL.get_internal_transaction(args) end - def get_by(%Transaction{} = transaction, args, resolution) do - if resolution.context.api_enabled do - transaction - |> GraphQL.transaction_to_internal_transactions_query() - |> Connection.from_query(&Repo.all/1, args, options(args)) - else - {:error, Helper.api_is_disabled()} - end + def get_by(%Transaction{} = transaction, args, _) do + transaction + |> GraphQL.transaction_to_internal_transactions_query() + |> Connection.from_query(&Repo.all/1, args, options(args)) end defp options(%{before: _}), do: [] diff --git a/apps/block_scout_web/lib/block_scout_web/graphql/resolvers/token.ex b/apps/block_scout_web/lib/block_scout_web/graphql/resolvers/token.ex index a830537b38..55092ec02e 100644 --- a/apps/block_scout_web/lib/block_scout_web/graphql/resolvers/token.ex +++ b/apps/block_scout_web/lib/block_scout_web/graphql/resolvers/token.ex @@ -1,19 +1,10 @@ defmodule BlockScoutWeb.GraphQL.Resolvers.Token do @moduledoc false - alias BlockScoutWeb.GraphQL.Resolvers.Helper alias Explorer.Chain.TokenTransfer alias Explorer.GraphQL - def get_by( - %TokenTransfer{token_contract_address_hash: token_contract_address_hash}, - _, - resolution - ) do - if resolution.context.api_enabled do - GraphQL.get_token(%{contract_address_hash: token_contract_address_hash}) - else - {:error, Helper.api_is_disabled()} - end + def get_by(%TokenTransfer{token_contract_address_hash: token_contract_address_hash}, _, _) do + GraphQL.get_token(%{contract_address_hash: token_contract_address_hash}) end end diff --git a/apps/block_scout_web/lib/block_scout_web/graphql/resolvers/token_transfer.ex b/apps/block_scout_web/lib/block_scout_web/graphql/resolvers/token_transfer.ex index 2302befd71..74fb50b52f 100644 --- a/apps/block_scout_web/lib/block_scout_web/graphql/resolvers/token_transfer.ex +++ b/apps/block_scout_web/lib/block_scout_web/graphql/resolvers/token_transfer.ex @@ -2,40 +2,27 @@ defmodule BlockScoutWeb.GraphQL.Resolvers.TokenTransfer do @moduledoc false alias Absinthe.Relay.Connection - alias BlockScoutWeb.GraphQL.Resolvers.Helper alias Explorer.Chain.{Address, TokenTransfer} alias Explorer.{GraphQL, Repo} - def get_by(%{transaction_hash: _, log_index: _} = args, resolution) do - if resolution.context.api_enabled do - GraphQL.get_token_transfer(args) - else - {:error, Helper.api_is_disabled()} - end + def get_by(%{transaction_hash: _, log_index: _} = args, _) do + GraphQL.get_token_transfer(args) end - def get_by(_, %{token_contract_address_hash: token_contract_address_hash} = args, resolution) do - if resolution.context.api_enabled do - connection_args = Map.take(args, [:after, :before, :first, :last]) + def get_by(_, %{token_contract_address_hash: token_contract_address_hash} = args, _) do + connection_args = Map.take(args, [:after, :before, :first, :last]) - token_contract_address_hash - |> GraphQL.list_token_transfers_query() - |> Connection.from_query(&Repo.replica().all/1, connection_args, options(args)) - else - {:error, Helper.api_is_disabled()} - end + token_contract_address_hash + |> GraphQL.list_token_transfers_query() + |> Connection.from_query(&Repo.replica().all/1, connection_args, options(args)) end - def get_by(%Address{hash: address_hash}, args, resolution) do - if resolution.context.api_enabled do - connection_args = Map.take(args, [:after, :before, :first, :last]) + def get_by(%Address{hash: address_hash}, args, _) do + connection_args = Map.take(args, [:after, :before, :first, :last]) - address_hash - |> TokenTransfer.token_transfers_by_address_hash(nil, [], nil) - |> Connection.from_query(&Repo.replica().all/1, connection_args, options(args)) - else - {:error, Helper.api_is_disabled()} - end + address_hash + |> TokenTransfer.token_transfers_by_address_hash(nil, [], nil) + |> Connection.from_query(&Repo.replica().all/1, connection_args, options(args)) end defp options(%{before: _}), do: [] diff --git a/apps/block_scout_web/lib/block_scout_web/graphql/resolvers/transaction.ex b/apps/block_scout_web/lib/block_scout_web/graphql/resolvers/transaction.ex index 3dbeb9924f..c1406eed85 100644 --- a/apps/block_scout_web/lib/block_scout_web/graphql/resolvers/transaction.ex +++ b/apps/block_scout_web/lib/block_scout_web/graphql/resolvers/transaction.ex @@ -2,43 +2,22 @@ defmodule BlockScoutWeb.GraphQL.Resolvers.Transaction do @moduledoc false alias Absinthe.Relay.Connection - alias BlockScoutWeb.GraphQL.Resolvers.Helper - alias Explorer.{Chain, GraphQL, Repo} + alias Explorer.{GraphQL, Repo} alias Explorer.Chain.{Address, TokenTransfer} - @api_true [api?: true] + def get_by(_, %{hash: hash}, _), + do: GraphQL.get_transaction_by_hash(hash) - def get_by(_, %{hash: hash}, resolution) do - with {:api_enabled, true} <- {:api_enabled, resolution.context.api_enabled}, - {:ok, transaction} <- Chain.hash_to_transaction(hash, @api_true) do - {:ok, transaction} - else - {:api_enabled, false} -> {:error, Helper.api_is_disabled()} - {:error, :not_found} -> {:error, "Transaction not found."} - end - end - - def get_by(%Address{hash: address_hash}, args, resolution) do + def get_by(%Address{hash: address_hash}, args, _) do connection_args = Map.take(args, [:after, :before, :first, :last]) - if resolution.context.api_enabled do - address_hash - |> GraphQL.address_to_transactions_query(args.order) - |> Connection.from_query(&Repo.replica().all/1, connection_args, options(args)) - else - {:error, Helper.api_is_disabled()} - end + address_hash + |> GraphQL.address_to_transactions_query(args.order) + |> Connection.from_query(&Repo.replica().all/1, connection_args, options(args)) end - def get_by(%TokenTransfer{transaction_hash: hash}, _, resolution) do - with {:api_enabled, true} <- {:api_enabled, resolution.context.api_enabled}, - {:ok, transaction} <- Chain.hash_to_transaction(hash, @api_true) do - {:ok, transaction} - else - {:api_enabled, false} -> {:error, Helper.api_is_disabled()} - {:error, :not_found} -> {:error, "Transaction not found."} - end - end + def get_by(%TokenTransfer{transaction_hash: hash}, _, _), + do: GraphQL.get_transaction_by_hash(hash) defp options(%{before: _}), do: [] diff --git a/apps/block_scout_web/lib/block_scout_web/graphql/schema.ex b/apps/block_scout_web/lib/block_scout_web/graphql/schema.ex index 1bfee0f8a4..2a01ac5b8f 100644 --- a/apps/block_scout_web/lib/block_scout_web/graphql/schema.ex +++ b/apps/block_scout_web/lib/block_scout_web/graphql/schema.ex @@ -4,9 +4,11 @@ defmodule BlockScoutWeb.GraphQL.Schema do use Absinthe.Schema use Absinthe.Relay.Schema, :modern - alias Absinthe.Middleware.Dataloader, as: AbsintheMiddlewareDataloader + alias Absinthe.Middleware.Dataloader, as: AbsintheDataloaderMiddleware alias Absinthe.Plugin, as: AbsinthePlugin + alias BlockScoutWeb.GraphQL.Middleware.ApiEnabled, as: ApiEnabledMiddleware + alias BlockScoutWeb.GraphQL.Resolvers.{ Address, Block, @@ -136,7 +138,11 @@ defmodule BlockScoutWeb.GraphQL.Schema do end end + def middleware(middleware, _field, _object) do + [ApiEnabledMiddleware | middleware] + end + def plugins do - [AbsintheMiddlewareDataloader] ++ AbsinthePlugin.defaults() + [AbsintheDataloaderMiddleware] ++ AbsinthePlugin.defaults() end end diff --git a/apps/explorer/lib/explorer/graphql.ex b/apps/explorer/lib/explorer/graphql.ex index e275631615..1492e68142 100644 --- a/apps/explorer/lib/explorer/graphql.ex +++ b/apps/explorer/lib/explorer/graphql.ex @@ -11,6 +11,8 @@ defmodule Explorer.GraphQL do where: 3 ] + alias Explorer.{Chain, Repo} + alias Explorer.Chain.{ Hash, InternalTransaction, @@ -19,7 +21,7 @@ defmodule Explorer.GraphQL do Transaction } - alias Explorer.Repo + @api_true [api?: true] @doc """ Returns a query to fetch transactions with a matching `to_address_hash`, @@ -96,6 +98,19 @@ defmodule Explorer.GraphQL do end end + @doc """ + Returns a transaction for a given hash. + """ + @spec get_transaction_by_hash(Hash.t()) :: {:ok, Transaction.t()} | {:error, String.t()} + def get_transaction_by_hash(hash) do + hash + |> Chain.hash_to_transaction(@api_true) + |> case do + {:ok, _} = result -> result + {:error, :not_found} -> {:error, "Transaction not found."} + end + end + @doc """ Returns a query to fetch token transfers for a token contract address hash.