API利用法
ElixirでのAPIプロジェクトの作成
Section titled “ElixirでのAPIプロジェクトの作成”ElixirのPhoenixフレームワークを使用して、API専用のプロジェクトを作成する方法を紹介します。以下の手順で、データベースを使用する場合と使用しない場合のプロジェクトを作成できます。
データベースありのAPIモード
Section titled “データベースありのAPIモード”データベースに接続してデータの永続化を伴うAPIを作成する場合、PhoenixプロジェクトはEctoをデフォルトで含みます。
-
プロジェクトの作成
- コマンド:
mix phx.new my_api --no-html --no-webpack - 説明:
HTMLやフロントエンドのビルドツールを含めず、バックエンドAPIに特化した構造を作成します。EctoとPostgreSQLへの接続設定も含まれます。
- コマンド:
-
リソースの生成とデータベース操作
mix ecto.create:config/dev.exsの設定に基づいて、データベースを作成します。mix phx.gen.json Accounts User users name:string:APIエンドポイントの作成を自動化します。Accountsというコンテキスト、Userというモデル、およびusersテーブルのマイグレーションファイルを生成します。mix ecto.migrate: データベースマイグレーションを実行し、usersテーブルを作成します。
フォルダ構成(データベースあり)
Section titled “フォルダ構成(データベースあり)”my_api/├── config/├── lib/│ ├── my_api/│ │ ├── accounts/│ │ │ ├── user.ex # Userモデル│ │ │ └── accounts.ex # コンテキストモジュール│ │ └── repo.ex # データベースリポジトリ│ └── my_api_web/│ ├── controllers/│ │ └── user_controller.ex # APIコントローラー│ └── router.ex # ルーター├── priv/│ └── repo/│ └── migrations/ # マイグレーションファイル└── ...データベースなしのAPIモード
Section titled “データベースなしのAPIモード”データベースを使用しない、純粋なAPI(例:外部APIのプロキシやインメモリデータのみを扱う場合)を作成するには、プロジェクト生成時に--no-ectoフラグを追加します。
-
プロジェクトの作成
- コマンド:
mix phx.new my_api --no-html --no-webpack --no-ecto - 説明:
Ecto関連の依存関係や設定ファイルを一切含みません。
- コマンド:
-
APIエンドポイントの手動作成
lib/my_api_web/controllers/api_controller.ex:APIエンドポイントのロジックを記述します。lib/my_api_web/router.ex: そのコントローラーへのルーティングを設定します。
フォルダ構成(データベースなし)
Section titled “フォルダ構成(データベースなし)”my_api/├── config/├── lib/│ └── my_api_web/│ ├── controllers/│ │ └── api_controller.ex # 手動で作成したコントローラー│ └── router.ex # ルーター├── priv/└── ...比較と使い分け
Section titled “比較と使い分け”| 特徴 | データベースありAPIモード | データベースなしAPIモード |
|---|---|---|
| 主な用途 | データの永続化が必要なAPI(例:ユーザー管理、ブログ投稿) | データベースを必要としないAPI(例:外部APIのプロキシ、計算サービス) |
| プロジェクト作成 | mix phx.new --no-html --no-webpack | mix phx.new --no-html --no-webpack --no-ecto |
| データ永続化 | ✅ Ectoによるデータベース接続 | ❌ データベース接続なし |
| リソース作成 | ✅ phx.gen.jsonジェネレーターが利用可能 | ❌ ジェネレーターは利用不可、手動で作成 |
| 利点 | 複雑なデータモデルを効率的に管理できる | 不要な依存関係がなく、軽量でシンプル |
| 考慮点 | 開発環境のセットアップ(Postgresなど)が必要 | すべてのAPIエンドポイントを手動で定義する必要がある |
どちらのモードを選択するかは、APIの目的によって決まります。データの読み書きが必要な場合はデータベースあり、外部サービスとの連携や単純な処理に特化する場合はデータベースなしが適しています。
EndpointとRouterの役割
Section titled “EndpointとRouterの役割”Phoenixフレームワークでは、Webリクエストの処理がEndpointとRouterという2つの主要なコンポーネントによって管理されます。これらは、リクエストの「入り口」と「交通整理役」として機能し、コードの役割を明確に分離します。
-
Endpoint: アプリケーションの玄関口 🚪-
Endpointは、Webリクエストがアプリケーションに到達する最初のポイントです。アプリケーションのHTTPサーバーとして機能し、ネットワーク接続の受付、初期設定、そしてすべてのリクエストをルーターに渡す役割を担います。 -
主な役割: 接続の受付、
SSL証明書の管理、リクエストの基本的なロギング、そしてPlugパイプラインの開始点。 -
設定例 (
config/config.exs): ポート番号やSSL設定が定義されます。
config/config.exs config :my_app, MyAppWeb.Endpoint,http: [port: 4000],url: [host: "localhost"],plug: MyAppWeb.Router -
-
Router: リクエストの交通整理役 🚦-
Routerは、Endpointが受け取ったリクエストを、URLに基づいて適切なコントローラーや処理ロジックに振り分ける役割を担います。 -
主な役割:
URLとHTTPメソッド(GET,POSTなど)を対応するコントローラーの関数にマッピングすること。 -
設定例 (
lib/my_app_web/router.ex):
lib/my_app_web/router.ex defmodule MyAppWeb.Router douse Phoenix.Routerimport Plug.Connpipeline :api doplug :accepts, ["json"]plug Plug.Parsers, parsers: [:json]endscope "/api", MyAppWeb dopipe_through :apiget "/users", UserController, :indexendend -
WebSocket通信:リアルタイムな連携 💬
Section titled “WebSocket通信:リアルタイムな連携 💬”Phoenixは、Phoenix Channelsという抽象化を通じて、WebSocket通信を簡単に実装できます。これにより、リアルタイムな双方向通信(例:チャット、ライブ更新)が可能になります。これは、従来のREST APIだけでは実現が難しい、Elixirの強みが特に活かされる部分です。
WebSocketの仕組みとReactとの連携
Section titled “WebSocketの仕組みとReactとの連携”-
Channelの定義: バックエンドで、特定のトピック(例:room:lobby)を購読するためのChannelモジュールを定義します。このモジュールは、クライアントからのメッセージを受け取り、処理し、ブロードキャストするロジックを保持します。 -
Socketの定義:lib/my_app_web/endpoint.exファイルで、WebSocket接続の入り口となるSocketを定義します。これは、クライアントが接続すべきエンドポイントになります。 -
Reactクライアントでの接続:Reactアプリケーションでは、phoenix.jsライブラリを使用してバックエンドに接続します。
Reactクライアントとの疎通例
Section titled “Reactクライアントとの疎通例”バックエンド (Elixir)
まず、WebSocketの入り口となるソケットをEndpointに定義します。
defmodule MyAppWeb.Endpoint do use Phoenix.Endpoint, otp_app: :my_app # ... 省略
socket "/socket", MyAppWeb.UserSocket, websocket: true, longpoll: false
# ... 省略end次に、メッセージを処理するChannelを定義します。
defmodule MyAppWeb.RoomChannel do use Phoenix.Channel
# クライアントがトピックに参加する際に呼び出される def join("room:" <> _room_name, _params, socket) do {:ok, socket} end
# クライアントからのメッセージを受信(`"new_msg"`イベント) def handle_in("new_msg", %{"body" => body}, socket) do # 受け取ったメッセージを同じトピックのすべてのクライアントにブロードキャスト broadcast!(socket, "new_msg", %{body: body, sender: "Server"}) {:noreply, socket} endendフロントエンド (React)
phoenix.jsライブラリを使用して、バックエンドのWebSocketエンドポイントに接続し、チャネルを購読します。
import { Socket } from "phoenix";
// WebSocketエンドポイントに接続let socket = new Socket("ws://localhost:4000/socket", {});socket.connect();
// 特定のトピックを購読するチャネルを作成let channel = socket.channel("room:lobby", {});
// チャネルへの接続を試行channel.join() .receive("ok", resp => console.log("Joined successfully", resp)) .receive("error", resp => console.log("Unable to join", resp));
// バックエンドからメッセージを受信channel.on("new_msg", payload => { console.log("Received a new message:", payload.body);});
// ボタンクリックなどでバックエンドにメッセージを送信document.getElementById("send-btn").onclick = () => { let message = "Hello from React!"; channel.push("new_msg", {body: message});};この連携により、リアルタイムなチャットアプリや、バックエンドでのデータ変更を即座にフロントエンドに反映するライブ更新機能などを、効率的に構築できます。
これらの例は、ElixirとPhoenixがAPI開発とリアルタイム通信の両方にいかに強力なツールであるかを示しています。ご質問があれば、いつでもお尋ねください。
PhoenixにおけるSPAの疎通方法
Section titled “PhoenixにおけるSPAの疎通方法”ElixirのPhoenixフレームワークで、ReactやVue.jsのような**SPA(Single Page Application)**と連携する場合、主に2つの方法があります。これらの方法は、それぞれ異なるユースケースと利点を持っています。
-
APIサーバーとして疎通する(REST API&WebSocket)-
これは最も一般的で柔軟なアプローチです。
PhoenixはAPIサーバーとして機能し、SPAはFetch APIやAxios、phoenix.jsライブラリなどを使ってバックエンドと通信します。 -
特徴
- 完全な分離: フロントエンドとバックエンドが完全に独立しています。これにより、それぞれを別のチームで開発したり、異なる技術スタックで構築したりすることが可能です。
- 汎用性: モバイルアプリや他のクライアント(
IoTデバイスなど)とも同じAPIを共有できます。 - 認証:
JWT(JSON Web Token)やセッションベースの認証など、標準的なAPI認証手法を使用します。 - リアルタイム通信:
Phoenix Channelsを通じてWebSocket通信を実装し、チャットやリアルタイム通知などの機能を簡単に構築できます。
-
実装例
Phoenixプロジェクトの作成:API専用プロジェクトとして作成します。
Terminal window mix phx.new my_api --no-html --no-webpack --no-liveAPIエンドポイント:REST APIとして、JSON形式でデータをやり取りします。
lib/my_app_web/router.ex scope "/api", MyAppWeb dopipe_through :apiget "/posts", PostController, :indexpost "/posts", PostController, :createendReactからのデータ取得:React側では、useEffectフックなどを使ってAPIを呼び出します。
import React, { useEffect, useState } from 'react';function PostsList() {const [posts, setPosts] = useState([]);useEffect(() => {fetch('/api/posts').then(response => response.json()).then(data => setPosts(data));}, []);return (<div>{posts.map(post => (<div key={post.id}>{post.title}</div>))}</div>);}
-
-
Phoenix LiveViewで疎通する-
LiveViewは、ElixirとPhoenixの最も革新的な機能の一つです。HTMLをサーバー側でレンダリングし、WebSocketを通じてHTMLの差分だけをクライアントに送信することで、JavaScriptをほとんど書かずにリッチなUIを実現します。 -
特徴
- サーバーサイドレンダリング: サーバー側でレンダリングを行うため、初期表示が高速です。
- 開発体験: サーバー側の
ElixirコードだけでUIのロジックを完結できるため、JavaScriptとElixirの間でコンテキストスイッチが不要になり、開発効率が大幅に向上します。 - リアルタイム性: ユーザーアクションは即座にサーバーに送信され、
UIの更新がWebSocket経由でリアルタイムに反映されます。 - ステート管理: アプリケーションの状態(
State)はすべてサーバーで管理されるため、フロントエンドの複雑なステート管理ライブラリ(Redux,Zustandなど)が不要になります。
-
実装例
- プロジェクトの作成:
LiveViewを含めてプロジェクトを作成します。
Terminal window mix phx.new my_appLiveViewコンポーネント: ユーザーがクリックするとカウントが増えるシンプルなカウンターの例です。
lib/my_app_web/live/counter_live.ex defmodule MyAppWeb.CounterLive douse MyAppWeb, :live_view@impl truedef mount(_params, _session, socket) do{:ok, assign(socket, count: 0)}end@impl truedef handle_event("increment", _params, socket) do{:noreply, update(socket, :count, &(&1 + 1))}endendHTMLテンプレート: ボタンがクリックされると、phx-click属性がサーバーのhandle_event関数を呼び出します。
<div><p>Count is: <%= @count %></p><button phx-click="increment">Increment</button></div>LiveViewは、このHTMLテンプレートをサーバーでレンダリングし、WebSocketを通じて変更を効率的に同期します。これにより、クライアント側ではHTMLと少量のJavaScriptだけで、動的なUIが実現されます。 - プロジェクトの作成:
-
どちらを選ぶべきか?
Section titled “どちらを選ぶべきか?”-
APIサーバーとして疎通:- おすすめのケース:
React Nativeのようなモバイルアプリや、複数の異なるクライアントをサポートする必要がある場合。フロントエンドとバックエンドの技術を完全に分離したいチーム。
- おすすめのケース:
-
LiveView:- おすすめのケース: 開発チームが
Elixirに精通しており、フロントエンドの複雑なステート管理やビルドプロセスを避けたい場合。リアルタイム性が重要で、UIを迅速に構築する必要がある場合。
- おすすめのケース: 開発チームが
LiveViewは、SPAの複雑さをサーバー側で吸収することで、開発の生産性を劇的に向上させます。しかし、既存のReactプロジェクトと統合する場合はAPIアプローチが適しています。どちらの方法も、Elixirの並行処理の強みを活かし、スケーラブルなアプリケーションを構築できます。