【问题标题】:Passing information from resolver to post-resolution middleware将信息从解析器传递到解析后中间件
【发布时间】:2019-11-02 22:53:12
【问题描述】:

我试图将信息从我的解析器函数传递到我的中间件,以便我可以在响应中设置一个 cookie。

用例是我想生成一个 Oauth2 授权链接,它允许客户端与第三方开始 Oauth2 流程。我想生成一个“状态”对象,我可以在响应中将其设置为 cookie。

我试过打电话

   %{resolution | context: state}

在解析器中,但不幸的是,这似乎并没有传递该状态。

这是我的解析器函数的简化示例

def get_oauth_link(_parent, _args, resolution) do
    state = random_string(10)

    part_one = "https://github.com/login/oauth/authorize"
    part_two = "?client_id=XXX"
    part_three = "&redirect_uri=http://localhost:3000/login/callback"
    part_four = "&state=" <> state
    part_five = "&scope=user:email"

    url = part_one <> part_two <> part_three <> part_four <> part_five

    # try to add the state to the resolution to 
    %{resolution | context: state}

    {:ok, url}
  end

然后在我的架构中

    @desc "Get oauth link"
    field :oauthlink non_null(:string) do
      resolve(&Resolvers.OauthResolver.get_oauth_link/3)

      # middleware after resolution to set a cookie with the provided state
      middleware fn resolution, _ ->
        # Here i want to extract the state generated in
        # the resolver and add to the context 
        IO.inspect(resolution, label: "Inside resolution")
      end
    end

我希望能够在此处记录的“absinthe_before_send”方法中设置 cookie:https://hexdocs.pm/absinthe_plug/Absinthe.Plug.html#module-before-send

这样做的最佳方法是什么?上面的方法对我来说似乎很直观,但状态在后解析中间件中不可用。

【问题讨论】:

    标签: elixir graphql absinthe


    【解决方案1】:

    您不能在解析器函数中更改分辨率。

    但是,您可以在中间件中更改分辨率。这就是中间件的用途。后解析器中间件解析将有一个 value 字段,其中包含解析器函数的结果(没有 :ok:error 原子)。

    您可以做的是从您的解析器函数中返回stateurl,然后在您的解析后中间件中,从解析value 字段中提取状态并将解析value 重置为url。像这样:

       def get_oauth_link(_parent, _args, resolution) do
        state = random_string(10)
    
        part_one = "https://github.com/login/oauth/authorize"
        part_two = "?client_id=XXX"
        part_three = "&redirect_uri=http://localhost:3000/login/callback"
        part_four = "&state=" <> state
        part_five = "&scope=user:email"
    
        url = part_one <> part_two <> part_three <> part_four <> part_five
    
        {:ok, %{url: url, state: state}} # return state and url
      end
    
    
       field :oauthlink, non_null(:string) do
          resolve(&Resolvers.OauthResolver.get_oauth_link/3)
          middleware fn %{value: %{state: state, url: url}=resolution, _ ->        
            resolution
            |> Map.put(:context, state) # set context using state
            |> Map.put(:value, url) # reset value to url
          end
       end
    

    【讨论】:

    • 几乎同时回答。 :-)
    【解决方案2】:

    我认为你不能像现在这样改变分辨率。

    说实话,我不明白为什么你不能只使用中间件进行设置。为什么不能只在中间件上生成?

    但是,我可以看到一种方法。

    @desc "Return api version"
    field :version, :version_payload do
      resolve(fn _, _ -> {:ok, %{version: OnCallAPI.version(), other: "Marcos"}} end)
    
      middleware fn resolution, _ ->
        # Here i want to extract the state generated in
        # the resolver and add to the context
        IO.inspect(resolution, label: "Inside resolution")
      end
    end
    

    如果您检查控制台,您会在values 上看到other。像这样:

    ...
    private: %{},
    root_value: %{},
    schema: OnCallAPIWeb.Schema,
    source: %{},
    state: :resolved,
    value: %{other: "Marcos", version: "0.30.0-rc"}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多