Phoenixフレームワーク完全ガイド
Phoenixフレームワーク完全ガイド
Section titled “Phoenixフレームワーク完全ガイド”Phoenixフレームワークを使用したWebアプリケーション開発を、実務で使える実装例とともに詳しく解説します。
1. Phoenixとは
Section titled “1. Phoenixとは”Phoenixの特徴
Section titled “Phoenixの特徴”Phoenixは、Elixirで書かれた高速でリアルタイムなWebアプリケーションフレームワークです。
Phoenixの特徴 ├─ 高速なパフォーマンス ├─ リアルタイム通信(WebSocket) ├─ フォールトトレランス └─ スケーラビリティなぜPhoenixが必要か
Section titled “なぜPhoenixが必要か”問題のある構成(Phoenixなし):
# 問題: 低レベルのHTTP処理を手動で実装defmodule SimpleServer do def start do # HTTPサーバーの実装が必要 # ルーティングの実装が必要 # ミドルウェアの実装が必要 endend解決: Phoenixによる高速なWebアプリケーション
# 解決: Phoenixがすべてを提供defmodule MyAppWeb.Router do use Phoenix.Router
pipeline :api do plug :accepts, ["json"] end
scope "/api", MyAppWeb do pipe_through :api get "/users", UserController, :index endend2. Phoenixプロジェクトの作成
Section titled “2. Phoenixプロジェクトの作成”基本的なプロジェクト作成
Section titled “基本的なプロジェクト作成”# Phoenixのインストールmix archive.install hex phx_new
# プロジェクトの作成mix phx.new my_app
# 依存関係のインストールcd my_appmix deps.get
# データベースの作成mix ecto.create
# サーバーの起動mix phx.serverAPI専用プロジェクトの作成
Section titled “API専用プロジェクトの作成”# API専用プロジェクトの作成mix phx.new my_api --no-html --no-webpack
# データベースなしのAPIプロジェクトmix phx.new my_api --no-html --no-webpack --no-ecto3. ルーティング
Section titled “3. ルーティング”基本的なルーティング
Section titled “基本的なルーティング”defmodule MyAppWeb.Router do use MyAppWeb, :router
pipeline :api do plug :accepts, ["json"] end
scope "/api", MyAppWeb do pipe_through :api
get "/users", UserController, :index post "/users", UserController, :create get "/users/:id", UserController, :show put "/users/:id", UserController, :update delete "/users/:id", UserController, :delete endendリソースルーティング
Section titled “リソースルーティング”# リソースルーティングの使用scope "/api", MyAppWeb do pipe_through :api
resources "/users", UserController # 以下と同等: # get "/users", UserController, :index # get "/users/:id", UserController, :show # post "/users", UserController, :create # put "/users/:id", UserController, :update # delete "/users/:id", UserController, :deleteend4. コントローラー
Section titled “4. コントローラー”基本的なコントローラー
Section titled “基本的なコントローラー”defmodule MyAppWeb.UserController do use MyAppWeb, :controller
alias MyApp.Accounts alias MyApp.Accounts.User
def index(conn, _params) do users = Accounts.list_users() render(conn, "index.json", users: users) end
def show(conn, %{"id" => id}) do user = Accounts.get_user!(id) render(conn, "show.json", user: user) end
def create(conn, %{"user" => user_params}) do case Accounts.create_user(user_params) do {:ok, user} -> conn |> put_status(:created) |> render("show.json", user: user)
{:error, changeset} -> conn |> put_status(:unprocessable_entity) |> render("error.json", changeset: changeset) end endend5. ビューとJSONレンダリング
Section titled “5. ビューとJSONレンダリング”JSONビューの定義
Section titled “JSONビューの定義”defmodule MyAppWeb.UserView do use MyAppWeb, :view
def render("index.json", %{users: users}) do %{data: render_many(users, UserView, "user.json")} end
def render("show.json", %{user: user}) do %{data: render_one(user, UserView, "user.json")} end
def render("user.json", %{user: user}) do %{ id: user.id, name: user.name, email: user.email, inserted_at: user.inserted_at } endend6. Phoenix LiveView
Section titled “6. Phoenix LiveView”LiveViewの基本
Section titled “LiveViewの基本”defmodule MyAppWeb.CounterLive do use MyAppWeb, :live_view
@impl true def mount(_params, _session, socket) do {:ok, assign(socket, count: 0)} end
@impl true def handle_event("increment", _params, socket) do {:noreply, update(socket, :count, &(&1 + 1))} end
@impl true def handle_event("decrement", _params, socket) do {:noreply, update(socket, :count, &(&1 - 1))} end
@impl true def render(assigns) do ~H""" <div> <h1>Count: <%= @count %></h1> <button phx-click="increment">+</button> <button phx-click="decrement">-</button> </div> """ endendルーティングでのLiveView
Section titled “ルーティングでのLiveView”defmodule MyAppWeb.Router do use MyAppWeb, :router
scope "/", MyAppWeb do pipe_through :browser
live "/counter", CounterLive endend7. Phoenix Channels(WebSocket)
Section titled “7. Phoenix Channels(WebSocket)”Channelの定義
Section titled “Channelの定義”defmodule MyAppWeb.RoomChannel do use Phoenix.Channel
def join("room:" <> room_id, _params, socket) do {:ok, socket} end
def handle_in("new_msg", %{"body" => body}, socket) do broadcast!(socket, "new_msg", %{ body: body, user: socket.assigns.user }) {:noreply, socket} end
def handle_out("new_msg", payload, socket) do push(socket, "new_msg", payload) {:noreply, socket} endendSocketの設定
Section titled “Socketの設定”defmodule MyAppWeb.UserSocket do use Phoenix.Socket
channel "room:*", MyAppWeb.RoomChannel
@impl true def connect(_params, socket, _connect_info) do {:ok, socket} end
@impl true def id(_socket), do: nilend8. 実務でのベストプラクティス
Section titled “8. 実務でのベストプラクティス”パターン1: コンテキストの使用
Section titled “パターン1: コンテキストの使用”defmodule MyApp.Accounts do @moduledoc """ Accountsコンテキスト """
alias MyApp.Accounts.User alias MyApp.Repo
def list_users do Repo.all(User) end
def get_user!(id) do Repo.get!(User, id) end
def create_user(attrs \\ %{}) do %User{} |> User.changeset(attrs) |> Repo.insert() endendパターン2: エラーハンドリング
Section titled “パターン2: エラーハンドリング”def create(conn, %{"user" => user_params}) do with {:ok, user} <- Accounts.create_user(user_params) do conn |> put_status(:created) |> render("show.json", user: user) else {:error, changeset} -> conn |> put_status(:unprocessable_entity) |> render("error.json", changeset: changeset) endend9. よくある問題と解決策
Section titled “9. よくある問題と解決策”問題1: ルーティングが動作しない
Section titled “問題1: ルーティングが動作しない”原因:
- パイプラインが正しく設定されていない
- スコープが間違っている
解決策:
# パイプラインの確認pipeline :api do plug :accepts, ["json"]end
# スコープの確認scope "/api", MyAppWeb do pipe_through :api # ルート定義end問題2: JSONが正しくレンダリングされない
Section titled “問題2: JSONが正しくレンダリングされない”原因:
- ビューが定義されていない
- render関数が正しく実装されていない
解決策:
# ビューの確認defmodule MyAppWeb.UserView do use MyAppWeb, :view
def render("show.json", %{user: user}) do %{data: render_one(user, UserView, "user.json")} endendこれで、Phoenixフレームワークの基礎知識と実務での使い方を理解できるようになりました。