Маршрутизация Phoenix на основе полезной нагрузки - PullRequest
1 голос
/ 02 августа 2020

Я реализую backend API в Elixir / Phoenix. По соображениям безопасности было решено показывать как можно меньше в URL-адресе, чтобы выполняемое действие было встроено в полезную нагрузку JSON запросов POST. Например, вместо того, чтобы иметь REST-подобный запрос https://my.server.com/api/get_user/42, мы выполним POST на https://my.server.com/api/ со следующей полезной нагрузкой:

{
    "action" : "get_user",
    "params" : {
        "id" : 42
    }
}

Пока мой маршрутизатор выглядит так:

  scope "/api", AlaaarmWeb do
     pipe_through :api

     post "/", ApiController, :process
     match :*, "/*path", ApiController, :error_404
   end

и у меня есть набор process функций, которые соответствуют шаблону на карте params:

  def process(conn, params = %{"action" => "get_user"}) do
    # ... get the user from the DB in resp, and sed back
    json(conn, resp)
  end

Он работает нормально, но код не очень понятен: один большой файл, используйте тот же контроллер, ApiController, хотя было бы гораздо понятнее иметь UserApiController для управления пользователями, ProductApiController для управления продуктами и т. д. c ..

Итак, я было интересно, есть ли способ сделать выбор модуля и функции для вызова также на основе содержимого полезной нагрузки, а не только на URL.

Ответы [ 2 ]

4 голосов
/ 02 августа 2020
• 1000 подключите, как это определено в конечной точке. ex перед плагином YourApp.Router call
  plug Plug.Session, @session_options
  plug UrlFromPayloadAction, []
  plug StackoverflowApiWeb.Router

Этот плагин изменяет информацию о пути, поэтому наш измененный URL-адрес будет анализироваться маршрутизатором, и мы можем определить контроллер, например post "/get_user/:id", ApiUserController, :process и другие, на основе определенного действия.

defmodule UrlFromPayloadAction do
        import Plug.Conn

        def init(default), do: default

        def call(%Plug.Conn{params: %{"action" => action,
                                         "params" => %{ "id" => id }
                                     }} = conn, _default) do
              conn = conn
                     |> assign(:original_path_info, conn.path_info)
                     |> assign(:original_request_path, conn.request_path)
               
              %Plug.Conn{conn | path_info: conn.path_info ++ [ "#{action}", "#{id}" ] , request_path: conn.request_path <> "/#{action}/#{id}" }
        end
        def call(conn, _default), do: conn
end

Это скорее изменчивый способ решения этой проблемы, который может противоречить общей философии функциональных фреймворков, таких как эликсир

0 голосов
/ 02 августа 2020

Нет, я не думаю, что Phoenix.Router может маршрутизировать на основе полезной нагрузки. Это должно быть сделано в контроллере.

Но вы все равно можете создавать отдельные файлы / модули контроллера, как вы описываете, и просто use их все в «главном» ApiController.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...