Phoenix模式Skill phoenix-patterns

Phoenix模式是Phoenix框架的开发最佳实践,涵盖上下文设计、控制器模式、插件管道和应用架构,用于构建高效、可维护的Elixir Web应用程序。关键词:Phoenix框架、Elixir、Web开发、上下文设计、控制器模式、插件、最佳实践、应用架构。

后端开发 0 次安装 0 次浏览 更新于 3/25/2026

name: phoenix-patterns user-invocable: false description: 当应用Phoenix Framework最佳实践时使用,包括上下文设计、控制器模式和应用架构。在构建Phoenix应用程序时使用。 allowed-tools:

  • Bash
  • Read

Phoenix模式

掌握Phoenix框架模式,以构建结构良好、可维护的Elixir Web应用程序。

上下文设计

上下文是专用模块,用于暴露和分组相关功能:

defmodule MyApp.Accounts do
  @moduledoc """
  Accounts上下文处理用户管理和认证。
  """

  alias MyApp.Repo
  alias MyApp.Accounts.User

  def list_users do
    Repo.all(User)
  end

  def get_user!(id), do: Repo.get!(User, id)

  def get_user_by_email(email) do
    Repo.get_by(User, email: email)
  end

  def create_user(attrs \\ %{}) do
    %User{}
    |> User.changeset(attrs)
    |> Repo.insert()
  end

  def update_user(%User{} = user, attrs) do
    user
    |> User.changeset(attrs)
    |> Repo.update()
  end

  def delete_user(%User{} = user) do
    Repo.delete(user)
  end

  def change_user(%User{} = user, attrs \\ %{}) do
    User.changeset(user, attrs)
  end
end

控制器模式

defmodule MyAppWeb.UserController do
  use MyAppWeb, :controller

  alias MyApp.Accounts
  alias MyApp.Accounts.User

  action_fallback MyAppWeb.FallbackController

  def index(conn, _params) do
    users = Accounts.list_users()
    render(conn, :index, users: users)
  end

  def create(conn, %{"user" => user_params}) do
    with {:ok, %User{} = user} <- Accounts.create_user(user_params) do
      conn
      |> put_status(:created)
      |> put_resp_header("location", ~p"/api/users/#{user}")
      |> render(:show, user: user)
    end
  end

  def show(conn, %{"id" => id}) do
    user = Accounts.get_user!(id)
    render(conn, :show, user: user)
  end

  def update(conn, %{"id" => id, "user" => user_params}) do
    user = Accounts.get_user!(id)

    with {:ok, %User{} = user} <- Accounts.update_user(user, user_params) do
      render(conn, :show, user: user)
    end
  end

  def delete(conn, %{"id" => id}) do
    user = Accounts.get_user!(id)

    with {:ok, %User{}} <- Accounts.delete_user(user) do
      send_resp(conn, :no_content, "")
    end
  end
end

回退控制器

defmodule MyAppWeb.FallbackController do
  use MyAppWeb, :controller

  def call(conn, {:error, :not_found}) do
    conn
    |> put_status(:not_found)
    |> put_view(json: MyAppWeb.ErrorJSON)
    |> render(:"404")
  end

  def call(conn, {:error, %Ecto.Changeset{} = changeset}) do
    conn
    |> put_status(:unprocessable_entity)
    |> put_view(json: MyAppWeb.ChangesetJSON)
    |> render(:error, changeset: changeset)
  end

  def call(conn, {:error, :unauthorized}) do
    conn
    |> put_status(:unauthorized)
    |> put_view(json: MyAppWeb.ErrorJSON)
    |> render(:"401")
  end
end

插件管道

defmodule MyAppWeb.Router do
  use MyAppWeb, :router

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_live_flash
    plug :put_root_layout, html: {MyAppWeb.Layouts, :root}
    plug :protect_from_forgery
    plug :put_secure_browser_headers
  end

  pipeline :api do
    plug :accepts, ["json"]
    plug MyAppWeb.Plugs.Authenticate
  end

  pipeline :admin do
    plug MyAppWeb.Plugs.RequireAdmin
  end

  scope "/", MyAppWeb do
    pipe_through :browser
    get "/", PageController, :home
  end

  scope "/api", MyAppWeb do
    pipe_through :api

    resources "/users", UserController, except: [:new, :edit]

    scope "/admin" do
      pipe_through :admin
      resources "/settings", Admin.SettingsController
    end
  end
end

自定义插件

defmodule MyAppWeb.Plugs.Authenticate do
  import Plug.Conn

  def init(opts), do: opts

  def call(conn, _opts) do
    with ["Bearer " <> token] <- get_req_header(conn, "authorization"),
         {:ok, user} <- MyApp.Accounts.verify_token(token) do
      assign(conn, :current_user, user)
    else
      _ ->
        conn
        |> put_status(:unauthorized)
        |> Phoenix.Controller.put_view(json: MyAppWeb.ErrorJSON)
        |> Phoenix.Controller.render(:"401")
        |> halt()
    end
  end
end

何时使用此技能

在以下情况下使用phoenix-patterns:

  • 结构化Phoenix应用架构
  • 设计上下文边界
  • 实现REST API控制器
  • 创建自定义认证/授权
  • 构建可重用的插件管道

最佳实践

  • 保持控制器精简,上下文丰富
  • 使用action_fallback进行错误处理
  • 在上下文中分组相关功能
  • 使用插件处理横切关注点
  • 在路由中遵循RESTful约定
  • 分离API和浏览器管道

常见陷阱

  • 将业务逻辑放在控制器中
  • 未使用上下文进行组织
  • 创建过于庞大的上下文
  • 忘记正确处理错误
  • 未有效使用管道
  • 在单个插件中混合关注点