You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Elixir/Phoenix控制器中运行GraphQL查询且保留CRUD网页

在Phoenix中同时保留CRUD页面并在控制器内执行GraphQL查询

你遇到的问题大概率是因为把Absinthe的插件全局挂载了,导致所有请求都被GraphQL接管,而非仅处理指定路径的请求。下面分两步帮你解决:

第一步:确保CRUD路由与GraphQL路由共存

首先检查你的lib/my_app_web/router.ex,别让GraphQL路由覆盖原有CRUD路由。正确的做法是保留原有资源路由,单独给GraphQL分配独立路径:

# 保留你之前生成的CRUD路由,比如文章管理
resources "/posts", PostController

# 单独挂载GraphQL端点,不会影响其他路由
forward "/graphql", Absinthe.Plug, schema: MyAppWeb.Schema

# 可选:添加GraphiQL调试界面,方便测试查询
forward "/graphiql", Absinthe.Plug.GraphiQL, schema: MyAppWeb.Schema, interface: :playground

同时,检查lib/my_app_web/endpoint.ex,不要把Absinthe.Plug加到全局的plug列表里(比如不要写plug Absinthe.Plug, schema: MyAppWeb.Schema),而是通过上面的路由forward来挂载。这样只有访问/graphql路径时才会走GraphQL逻辑,原来的CRUD页面(比如/posts)依然可以正常访问。

如果你的GraphQL需要使用会话或浏览器管道的功能,可以给它单独指定管道:

scope "/graphql" do
  pipe_through :browser # 若是API场景就用:api管道
  forward "/", Absinthe.Plug, schema: MyAppWeb.Schema
end

第二步:在控制器内执行GraphQL查询

要是想在Phoenix控制器里直接运行GraphQL查询(不用通过HTTP请求到/graphql),可以用Absinthe.run/3函数直接调用你的Schema。举个改造PostController的例子:

defmodule MyAppWeb.PostController do
  use MyAppWeb, :controller

  # 引入你的GraphQL Schema
  alias MyAppWeb.Schema

  def index(conn, _params) do
    # 定义要执行的GraphQL查询
    query = """
    query GetAllPosts {
      posts {
        id
        title
        body
      }
    }
    """

    # 执行查询,还可以传递上下文(比如当前用户、conn信息)给Resolver
    case Absinthe.run(query, Schema, context: %{conn: conn}) do
      {:ok, %{data: %{posts: posts}}} ->
        # 拿到数据后,和原来一样渲染CRUD页面
        render(conn, "index.html", posts: posts)

      {:error, errors} ->
        # 处理查询错误,比如返回错误页面
        conn
        |> put_status(:internal_server_error)
        |> render("error.html", errors: errors)
    end
  end

  # 再举个带变量的查询例子,比如根据ID获取单篇文章
  def show(conn, %{"id" => id}) do
    query = """
    query GetPost($id: ID!) {
      post(id: $id) {
        id
        title
        body
      }
    }
    """

    # 传递变量给查询
    variables = %{"id" => id}

    case Absinthe.run(query, Schema, variables: variables, context: %{conn: conn}) do
      {:ok, %{data: %{post: post}}} ->
        render(conn, "show.html", post: post)

      {:error, errors} ->
        conn
        |> put_status(:not_found)
        |> render("not_found.html", errors: errors)
    end
  end
end

这样你既可以保留原来的CRUD页面,又能在控制器里利用GraphQL的查询能力,甚至可以逐步把原来的数据库查询替换成GraphQL查询。

小提示

  • 你的Resolver函数可以通过context参数拿到你传递的信息,比如当前用户,方便做权限验证之类的逻辑。
  • 如果是API场景,也可以用同样的方法在API控制器里执行GraphQL查询,返回JSON格式的数据。

内容的提问来源于stack exchange,提问作者Errol Hassall

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 10:15:59