如何在不删除生成的CRUD网页的情况下运行Elixir/Phoenix控制器中的GraphQl查询



我已经在elixir中创建了一个凤凰应用程序。我使用了生成工具来创建所有CRUD功能和CRUD页面。

当前使用:

def index(conn, _params) do
  data = Repo.all(Object)
  render(conn, "index.html", data: data)
end

如何用GraphQl实现替换它,因为我目前有能力通过指定的URL传递GraphQl查询。从表中获取所有记录。该文档谈论了使用Absinthe_phoenix插头并将其添加到管道中。最终,这只是替换我拥有并要求URL的当前网页,所有当前页面都是Phoenix运行脚手架命令以生成CRUD和数据库架构时创建的页面。

。 。

我需要保留所有这些CRUD页面,但让它们运行grapql查询。因此,在显示数据库中所有记录的页面上,我需要它而不是运行

data = Repo.all(Object)

它应该运行

{
  objects{
    field1,
    field2
  }
}

获取所有数据。如何在控制器中运行GraphQl查询?

这是我需要在GraphQL架构中运行的查询

query do
    @doc """
    Returns all the records from a database
    """
    field :objects, list_of(:object) do
        resolve &Billingplus.ObjectResolver.all/2
    end
end

您需要在GQL架构中创建引用,并具有针对不同事物的解析器函数。您不会将其放在控制器中。我将向您展示一个从DB到Absinthe实施的"事物"的前后示例。

休息和GQL是不同的范式/接口。

您的项目中有没有工作的GQL?展示您所做的事情,以便我们提供建议。

示例突变:

mutation do
    @desc "Create an OAuth2 client"
    field :create_oauth2_client, :oauth2_client do
      arg(:app_id, non_null(:uuid4))
      arg(:client_id, non_null(:string))
      arg(:client_secret, non_null(:string))
      arg(:oauth2_provider_id, non_null(:uuid4))
      resolve(&Resolvers.OAuth2Client.create_oauth2_client/3)
    end
end

示例查询:

query do
    @desc "Get an OAuth2 client"
    field :oauth2_client, :oauth2_client do
      arg(:id, non_null(:uuid4))
      resolve(&Resolvers.OAuth2Client.get_oauth2_client/3)
    end
end

示例模式对象:

defmodule ApiWeb.Schema.OAuth2Client do
  use Absinthe.Schema.Notation
  alias Api.Auth.Apps
  alias Api.Auth.OAuth2Providers
  alias Api.Util
  @desc "An OAuth2 client"
  object :oauth2_client do
    field(:id, :uuid4)
    field(:client_id, :string)
    field(:client_secret, :string)
    field(:app, :app,
      resolve: fn oauth2_client, _, _ ->
        Apps.get_app(oauth2_client.app_id)
        |> Util.handle_not_found_error_and_wrap("App not found.")
      end
    )
    field(:oauth2_provider, :oauth2_provider,
      resolve: fn oauth2_client, _, _ ->
        OAuth2Providers.get_oauth2_provider(oauth2_client.oauth2_provider_id)
        |> Util.handle_not_found_error_and_wrap("OAuth2Provider not found.")
      end
    )
  end
end

示例解析器:

defmodule ApiWeb.Resolvers.OAuth2Client do
  alias Api.Auth.OAuth2Clients
  #
  # QUERIES
  #
  def get_oauth2_client(_parent, %{id: id}, _resolution) do
    OAuth2Clients.get_oauth2_client(id)
  end
  def get_oauth2_clients_by_app(_parent, %{app_id: app_id}, _resolution) do
    OAuth2Clients.get_oauth2_clients_by_app(app_id)
  end
  #
  # MUTATIONS
  #
  def create_oauth2_client(_parent, params, _resolution) do
    OAuth2Clients.create_oauth2_client(%{
      app_id: params.app_id,
      oauth2_provider_id: params.oauth2_provider_id,
      client_id: params.client_id,
      client_secret: params.client_secret
    })
  end
end

示例上下文:

defmodule Api.Auth.OAuth2Clients do
  @moduledoc """
  The OAuth2Clients context.
  """
  import Ecto.Query, warn: false
  alias Api.Repo
  alias Api.Auth.OAuth2Clients.OAuth2Client
  alias Api.Util
  @doc """
  Returns the list of OAuth2Clients.
  ## Examples
      iex> list_oauth2_clients()
      {:ok, [%OAuth2Client{}, ...]}
  """
  def list_oauth2_clients do
    Repo.all(OAuth2Client)
    |> Util.handle_not_found_error_and_wrap("No OAuth2Clients found.")
  end
  @doc """
  Gets a single OAuth2Client.
  Returns `{:error, %NotFoundError{}}` if the OAuth2Client does not exist.
  ## Examples
      iex> get_oauth2_client(123)
      {:ok, %OAuth2Client{}}
      iex> get_oauth2_client(456)
      {:error, %NotFoundError{}}
  """
  def get_oauth2_client(id) do
    Repo.get(OAuth2Client, id)
    |> Util.handle_not_found_error_and_wrap("OAuth2Client not found.")
  end
  @doc """
  Gets a single OAuth2Client by `client_id` and `provider_id`.
  Returns `{:error, %NotFoundError{}}` if the OAuth2Client does not exist.
  ## Examples
      iex> get_oauth2_client_by_client_and_provider_id(123)
      {:ok, %OAuth2Client{}}
      iex> get_oauth2_client_by_client_and_provider_id(456)
      {:error, %NotFoundError{}}
  """
  def get_oauth2_client_by_client_and_provider_id(client_id, provider_id) do
    from(o in OAuth2Client,
      where: o.client_id == ^client_id and o.oauth2_provider_id == ^provider_id
    )
    |> Repo.one()
    |> Util.handle_not_found_error_and_wrap("OAuth2Client not found.")
  end
  @doc """
  Gets a list of OAuth2Client by App.
  Returns `{:error, %NotFoundError{}}` if there are no OAuth2Client to return.
  ## Examples
      iex> get_oauth2_clients_by_app(123)
      {:ok, [%OAuth2Client{}, ...]}
      iex> get_oauth2_clients_by_app(456)
      {:error, %NotFoundError{}}
  """
  def get_oauth2_clients_by_app(app_id) do
    from(o in OAuth2Client,
      where: o.app_id == ^app_id
    )
    |> Repo.all()
    |> Util.handle_not_found_error_and_wrap("App not found.")
  end
  @doc """
  Gets an OAuth2Client by `App` and `Provider`
  Returns `{:error, %NotFoundError{}}` if there is no `OAuth2Client` to return.
  ## Examples
      iex> get_oauth2_clients_by_app_and_provider(123)
      {:ok, [%OAuth2Client{}, ...]}
      iex> get_oauth2_clients_by_app_and_provider(456)
      {:error, %NotFoundError{}}
  """
  def get_oauth2_client_by_app_and_provider(app_id, provider_id) do
    from(o in OAuth2Client,
      where: o.app_id == ^app_id and o.oauth2_provider_id == ^provider_id
    )
    |> Repo.one()
    |> Util.handle_not_found_error_and_wrap("App not found.")
  end
  @doc """
  Creates an OAuth2Client.
  ## Examples
      iex> create_oauth2_client(%{field: value})
      {:ok, %OAuth2Client{}}
      iex> create_oauth2_client(%{field: bad_value})
      {:error, %Ecto.Changeset{}}
  """
  def create_oauth2_client(attrs) do
    %OAuth2Client{}
    |> OAuth2Client.create(attrs)
    |> Repo.insert()
  end
  @doc """
  Updates an OAuth2Client.
  ## Examples
      iex> update_oauth2_client(oauth2_client, %{field: new_value})
      {:ok, %OAuth2Client{}}
      iex> update_oauth2_client(oauth2_client, %{field: bad_value})
      {:error, %Ecto.Changeset{}}
  """
  def update_oauth2_client(%OAuth2Client{} = oauth2_client, attrs) do
    oauth2_client
    |> OAuth2Client.update(attrs)
    |> Repo.update()
  end
  @doc """
  Deletes a OAuth2Client.
  ## Examples
      iex> delete_oauth2_client(oauth2_client)
      {:ok, %OAuth2Client{}}
      iex> delete_oauth2_client(oauth2_client)
      {:error, %Ecto.Changeset{}}
  """
  def delete_oauth2_client(%OAuth2Client{} = oauth2_client) do
    Repo.delete(oauth2_client)
  end
end

示例模型/模型:

defmodule Api.Auth.OAuth2Clients.OAuth2Client do
  use Ecto.Schema
  import Ecto.Changeset
  alias Api.Auth.Apps.App
  alias Api.Auth.OAuth2Providers.OAuth2Provider
  @primary_key {:id, :binary_id, autogenerate: true}
  @foreign_key_type :binary_id
  schema "oauth2_clients" do
    field(:client_id, :string)
    field(:client_secret, :string)
    belongs_to(:app, App)
    belongs_to(:oauth2_provider, OAuth2Provider)
    timestamps()
  end
  def create(app, attrs) do
    app
    |> cast(attrs, [:client_id, :client_secret, :oauth2_provider_id, :app_id])
    |> validate_required([:client_id, :client_secret, :oauth2_provider_id, :app_id])
    |> foreign_key_constraint(:app_id)
    |> foreign_key_constraint(:oauth2_provider_id)
  end
  def update(app, attrs) do
    app
    |> cast(attrs, [:client_id, :client_secret, :oauth2_provider_id, :app_id])
    |> foreign_key_constraint(:app_id)
    |> foreign_key_constraint(:oauth2_provider_id)
  end
end

示例迁移:

defmodule Api.Repo.Migrations.CreateOAuth2Clients do
  use Ecto.Migration
  def change do
    create table(:oauth2_clients, primary_key: false) do
      add(:id, :binary_id, primary_key: true)
      add(:client_id, :string, null: false)
      add(:client_secret, :string, null: false)
      add(:oauth2_provider_id, references(:oauth2_providers, type: :binary_id), null: false)
      add(:app_id, references(:apps, type: :binary_id), null: false)
      timestamps()
    end
  end
  def up do
    create(
      constraint(:owners, :user_or_organization,
        check:
          "((organization_id is not null and user_id is null) or (organization_id is null and user_id is not null))"
      )
    )
  end
  def down do
    drop(constraint(:owners, :user_or_organization))
  end
end

这是您感到困惑的地方。您没有在路由器中引用控制器,而是指定GQL端点并在此处查询后端。

defmodule ApiWeb.Router do
  use ApiWeb, :router
  alias ApiWeb.OAuthController
  pipeline :api do
    plug(Plug.Parsers,
      parsers: [:json, Absinthe.Plug.Parser],
      pass: ["*/*"],
      json_decoder: Jason
    )
    plug(:accepts, ["json"])
  end
  scope "/" do
    pipe_through(:api)
    get("/oauth2", OAuthController, :callback)
    post("/graphql", Absinthe.Plug, schema: ApiWeb.Schema)
    forward("/graphiql", Absinthe.Plug.GraphiQL,
      schema: ApiWeb.Schema,
      json_codec: Jason
    )
  end
end

在凤凰项目中实现苦艾酒有很多不同的组成部分。我花了一段时间将我的头缠绕在上面 - 主要是因为对象定义有点奇怪,您可以制作伪虚拟字段。首先,在查询内解决结构参考的能力也有些混乱。

最新更新