【问题标题】:Versioning API in Elixir PlugElixir Plug 中的版本控制 API
【发布时间】:2019-09-08 02:00:14
【问题描述】:

我有两个模块:lib/endpoints/v1/base.ex 和 lib/endpoints/v2/base.ex。

lib/endpoints/v1/base.ex

defmodule Http.Endpoints.V1.Base do
  require Logger
  use Plug.Router

  plug(:match)
  plug(:dispatch)
  plug(Plug.Logger)
  plug(Plug.Parsers, parsers: [:json], json_decoder: Poison)

  get "/v1/ping" do
    send_resp(conn, 200, "pong!")
  end
end

lib/endpoints/v2/base.ex

defmodule Http.Endpoints.V2.Base do
  require Logger
  use Plug.Router

  plug(:match)
  plug(:dispatch)
  plug(Plug.Logger)
  plug(Plug.Parsers, parsers: [:json], json_decoder: Poison)

  get "/v2/ping" do
    send_resp(conn, 200, "pong! 2")
  end
end

如果我将孩子放入 applications.ex,我的端点可以正常工作

Plug.Cowboy.child_spec(scheme: :http, plug: Http.Endpoints.V1.Base, options: [port: Application.get_env(:http, :port)])

但我希望我的应用程序启动所有端点版本。

我尝试使用 require Http.Endpoints.V1.Base 和 require Http.Endpoints.V2.Base 创建 lib/endpoints.ex 并更改了我的 applications.ex 但它不起作用。

【问题讨论】:

    标签: elixir plug


    【解决方案1】:

    您可以从端点文件转发到其他路由器。以下是forward/2 函数的文档:https://hexdocs.pm/plug/Plug.Router.html#forward/2

    基本上你为 v1 和 v2 创建了 2 个路由器:

    defmodule MyAppWeb.V2.Router do
      use Plug.Router
    
      plug :match
      plug :dispatch
    
      get "/ping" do
        send_resp(conn, 200, "OK")
      end
    end
    

    和

    defmodule MyAppWeb.V1.Router do
      use Plug.Router
    
      plug :match
      plug :dispatch
    
      get "/ping" do
        send_resp(conn, 200, "OK")
      end
    end
    

    然后在您的端点中,您可以添加所有常用功能并转发到您的版本化路由,如下所示:

    defmodule MyAppWeb.Endpoint do
      require Logger
      use Plug.Router
    
      plug :match
      plug :dispatch
      plug Plug.Logger
      plug Plug.Parsers, parsers: [:json], json_decoder: Poison
    
      # Forwarding
      forward "/v2", to: MyApp.V2.Router
      forward "/v1", to: MyApp.V1.Router
    
      # You should put a catch-all here
      match _ do
        send_resp(conn, 404, "Not Found")
      end
    end
    

    然后在您的 application.ex 文件中,像以前一样挂载您的端点。但是,此时您应该能够从同一个端口同时 ping /v1/ping 和 /v2/ping。

    干杯!

    【讨论】:

    • 难道我们也不必在子路由器上进行匹配和调度吗?
    • 我不是 100% 确定它是必需的,但我记得过去必须这样做。
    • 我刚试过,绝对需要。代码编译为Plug.Router暴露了init/1和call/2,但是如果我们不在子路由器的管道中添加:match和:dispatch,连接就会挂起或者干脆失败(因为它赢了'不被传递到路由器模块中配置的路径)。我将它们添加到答案中,以节省人们尝试此操作的时间。
    【解决方案2】:

    如果我将 applications.ex 放入我的端点可以正常工作 孩子们

    Plug.Cowboy.child_spec(
       scheme: :http, 
       plug: Http.Endpoints.V1.Base, 
       options: [port: Application.get_env(:http, :port)]
    )
    

    指定它的现代方式是:

    {Plug.Cowboy, [[ 
          scheme: :http, 
          plug: Http.Endpoints.V1.Base, 
          options: [port: Application.get_env(:http, :port)]
        ]]
    }
    

    见:https://hexdocs.pm/elixir/Supervisor.html#module-child_spec-1

    不过,在我看来,直接调用child_spec() 似乎更容易,而不是试图计算出参数周围需要多少个括号。

    【讨论】:

      猜你喜欢
      • 2015-06-11
      • 2022-01-12
      • 1970-01-01
      • 2017-03-18
      • 2017-09-23
      • 2012-05-31
      • 2016-05-22
      • 2016-03-21
      • 1970-01-01
      相关资源
      最近更新 更多