如何在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
相关产品推荐
相关产品推荐

