fukuoka.ex代表のpiacereです
ご覧いただいて、ありがとうございます
前回、インストールした、ElixirのWebフレームワーク「Phoenix」の新バージョン1.4で、DBと紐付くAPIを作ってみます
なお、Phoenix 1.4正式版のEctoは、メジャーバージョンアップした3.0になっているので、その試しにもなっています
この連載の、前回までの記事は、以下になります
|> Phoenix 1.4正式版① インストール編
あと、参考までに、rc版を試したときのコラムは、以下になります
|> Phoenix 1.4rcを試す① アップデート紹介編
|> Phoenix 1.4rcを試す② インストール編(不具合時の復旧もあるよ)
|> Phoenix 1.4rcを試す③ ローカルSSL開発編(Gigalixirのオマケ付)
|> Phoenix 1.4rcを試す④ webpack編
内容が、面白かったり、気に入ったら、「いいね」よろしくお願いします
事前準備:PostgreSQLをインストール
今回、DBを利用するため、PostgreSQLをあらかじめインストールする必要があります
以前、書いたコラムをご参考ください
DBを使うPhoenixのPJ作成、DB作成、起動
DB利用有のPhoenix PJを作成します
なお、PJ名に「Web」という文字列を含むと、フォルダ作成やモジュール命名の都合から、不具合が出るため、入れないよう気を付けてください(エラーメッセージから判断付けるのは、かなり困難なので、ご注意を)
mix phx.new phx14_db --no-webpack
…(ファイル作成ログが続く)…
Fetch and install dependencies? [Yn] (←y、Enterを入力)
実際にインストールされたCowboyやEctoのバージョンが、幾つなのか、ライブラリバージョンを確認するため、mix.lockを見てみましょう
%{
"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [], [], "hexpm"},
"cowboy": {:hex, :cowboy, "2.5.0", "4ef3ae066ee10fe01ea3272edc8f024347a0d3eb95f6fbb9aed556dacbfc1337", [], [{:cowlib, "~> 2.6.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.6.2", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"},
"cowlib": {:hex, :cowlib, "2.6.0", "8aa629f81a0fc189f261dc98a42243fa842625feea3c7ec56c48f4ccdb55490f", [], [], "hexpm"},
"db_connection": {:hex, :db_connection, "2.0.1", "09454c6c6e8e4295f400b72580b19f0ac68fda2602e209533285206cb99bee6b", [], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm"},
"decimal": {:hex, :decimal, "1.5.0", "b0433a36d0e2430e3d50291b1c65f53c37d56f83665b43d79963684865beab68", [], [], "hexpm"},
"ecto": {:hex, :ecto, "3.0.1", "a26605ee7b243a754e6609d1c23da27bcb22823659b07bf03f9020da92a8e4f4", [], [{:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}], "hexpm"},
"ecto_sql": {:hex, :ecto_sql, "3.0.0", "8d1883376bee02a0e76b5ef797e39d04333c34b9935d0b4785dbf3cbdb571e2a", [], [{:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.9.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.14.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.2.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
"file_system": {:hex, :file_system, "0.2.6", "fd4dc3af89b9ab1dc8ccbcc214a0e60c41f34be251d9307920748a14bf41f1d3", [], [], "hexpm"},
"gettext": {:hex, :gettext, "0.16.0", "4a7e90408cef5f1bf57c5a39e2db8c372a906031cc9b1466e963101cb927dafc", [], [], "hexpm"},
"jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"},
"mime": {:hex, :mime, "1.3.0", "5e8d45a39e95c650900d03f897fbf99ae04f60ab1daa4a34c7a20a5151b7a5fe", [], [], "hexpm"},
"phoenix": {:hex, :phoenix, "1.4.0", "56fe9a809e0e735f3e3b9b31c1b749d4b436e466d8da627b8d82f90eaae714d2", [], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.0.0", "c43117a136e7399ea04ecaac73f8f23ee0ffe3e07acfcb8062fe5f4c9f0f6531", [], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"phoenix_html": {:hex, :phoenix_html, "2.12.0", "1fb3c2e48b4b66d75564d8d63df6d53655469216d6b553e7e14ced2b46f97622", [], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.2.0", "3bb31a9fbd40ffe8652e60c8660dffd72dd231efcdf49b744fb75b9ef7db5dd2", [], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.1", "6668d787e602981f24f17a5fbb69cc98f8ab085114ebfac6cc36e10a90c8e93c", [], [], "hexpm"},
"plug": {:hex, :plug, "1.7.1", "8516d565fb84a6a8b2ca722e74e2cd25ca0fc9d64f364ec9dbec09d33eb78ccd", [], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}], "hexpm"},
"plug_cowboy": {:hex, :plug_cowboy, "2.0.0", "ab0c92728f2ba43c544cce85f0f220d8d30fc0c90eaa1e6203683ab039655062", [], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [], [], "hexpm"},
"postgrex": {:hex, :postgrex, "0.14.0", "f3d6ffea1ca8a156e0633900a5338a3d17b00435227726baed8982718232b694", [], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"},
"ranch": {:hex, :ranch, "1.6.2", "6db93c78f411ee033dbb18ba8234c5574883acb9a75af0fb90a9b82ea46afa00", [], [], "hexpm"},
"telemetry": {:hex, :telemetry, "0.2.0", "5b40caa3efe4deb30fb12d7cd8ed4f556f6d6bd15c374c2366772161311ce377", [], [], "hexpm"},
}
Cowboyが2.5、Ectoが3.0.1であることが確認できました
Telemetryもインストールされていますね
参考までに、mix.exsも見ておきましょう
…
defp deps do
[
{:phoenix, "~> 1.4.0"},
{:phoenix_pubsub, "~> 1.1"},
{:phoenix_ecto, "~> 4.0"},
{:ecto_sql, "~> 3.0"},
{:postgrex, ">= 0.0.0"},
{:phoenix_html, "~> 2.11"},
{:phoenix_live_reload, "~> 1.2", only: :dev},
{:gettext, "~> 0.11"},
{:jason, "~> 1.0"},
{:plug_cowboy, "~> 2.0"}
]
end
…
CowboyやTelemetryの個別記載が無いことから、Phoenix 1.4かEctoの依存に含まれたことが確認できます(詳しくは、HexのDependenciesを追ってください)
PostgreSQLのパスワードが、「postgres」で無い場合は、下記の「password」項目の修正が必要です
…
# Configure your database
config :phx14_db, Phx14Db.Repo,
username: "postgres",
password: "postgres",
database: "blog_dev",
hostname: "localhost",
pool_size: 10
おや?「adapter: Ecto.Adapters.Postgres,」の記載が無くなっていますね…これで動くのかしら?
まぁ、ひとまず、DBを作成します ※作成しないとiex内でエラー連発となるのでお忘れなく
cd phx14_db
mix ecto.create
作成できました(PostgreSQL側も、念のため確認しましたが、無事、作られていました)
Phoenixを起動します
iex -S mix phx.server
Phoenix起動の際、以下ログが出ていれば起動成功です
…
[info] Running BlogWeb.Endpoint with cowboy 2.5.0 at http://localhost:4000
Interactive Elixir (1.7.4) - press Ctrl+C to exit (type h() ENTER for help)
iex>
ブラウザで「http://localhost:4000
」をアクセスすると、以下ページが表示されます
PhoenixでDBアクセスするAPIを作る
以下コマンドで、DBアクセスするAPIを作ります
Ctrl+cを2回押して、一度、Phoenixを停止してから、コマンドを入力します
mix phx.gen.json Api Post posts title:string body:text
以下ログと、実行後の作業指示が示されます
* creating lib/blog_web/controllers/post_controller.ex
* creating lib/blog_web/views/post_view.ex
* creating test/blog_web/controllers/post_controller_test.exs
* creating lib/blog_web/views/changeset_view.ex
* creating lib/blog_web/controllers/fallback_controller.ex
* creating lib/blog/api/post.ex
* creating priv/repo/migrations/20181110064453_create_posts.exs
* creating lib/blog/api/api.ex
* injecting lib/blog/api/api.ex
* creating test/blog/api/api_test.exs
* injecting test/blog/api/api_test.exs
Add the resource to your :api scope in lib/blog_web/router.ex:
resources "/posts", PostController, except: [:new, :edit]
Remember to update your repository by running migrations:
$ mix ecto.migrate
まず、ルーティングにAPI用エントリーとして、上記「resources "/posts", ~」を、「get "/", ~」直下に追記します
defmodule Phx14DbWeb.Router do
use Phx14DbWeb, :router
…
scope "/", Phx14DbWeb do
pipe_through :browser # Use the default browser stack
get "/", PageController, :index
resources "/posts", PostController, except: [:new, :edit]
end
…
マイグレートします
mix ecto.migrate
以下ログのように、テーブルが作成されます
[debug] QUERY OK source="schema_migrations" db=0.0ms
SELECT s0."version"::bigint FROM "schema_migrations" AS s0 FOR UPDATE []
[info] == Running 20181110064453 Phx14Db.Repo.Migrations.CreatePosts.change/0 forward
[info] create table posts
[info] == Migrated 20181110064453 in 0.0s
Phoenix 1.3+Ecto 2系のときと、ログが少し変わってました
では、Phoenixを起動してください
iex -S mix phx.server
APIでDBへのデータ投入、読み込み
では、APIでデータ投入してみましょう
APIを叩くために、REST APIクライアントが必要ですが、Firefoxの「RESTClient」、Chromeの「Postman」が便利です
Firefox「RESTClient」
https://addons.mozilla.org/ja/firefox/addon/restclient/
Chrome「Postman」
https://chrome.google.com/webstore/detail/postman/fhbjgbiflinjbdggehcddcbncdddomop
ここでは、FirefoxのRESTClientをインストールして、使ってみます
まず、RESTClientの「Headers」メニューで、「Custom Header」を選択して、REST API用のヘッダー設定をします
次に、URLに「http://localhost:4000/posts
」を入れ、「Method」を「POST」に変更し、「Body」に以下を入力します
{ "post": { "title": "t1", "body": "b1" } }
「SEND」ボタンをクリックすると、以下の通り、エラーになります
「Response」の中身を見てみると、CSRFトークンエラーが出ています
これは、リクエストにCSRFトークンが付与されていないことが原因ですが、ステートレスなAPIでCSRF対応するのは本筋から外れるので、いったんシンプルに、router.exに設定されているSCRF対策を解除します
defmodule Phx14DbWeb.Router do
use Phx14DbWebWeb, :router
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
# plug :protect_from_forgery
plug :put_secure_browser_headers
end
…
コンパイルします
iex> recompile
「Method」を「GET」に切り替え、「SEND」ボタンをクリックすると、投入したデータが返っていることが確認できます
終わり
Phoenix 1.4でも、1.3時と変わらず、DB+APIがサクっと作れました
次回は、GraphQLライブラリ「Absinthe」をPhoenix 1.4にて動かしてみようと思います