LoginSignup
10
19

More than 5 years have passed since last update.

Phoenix(Elixir)でJSONを返すシンプルなWebAPIを作成

Last updated at Posted at 2017-02-14

最近、なにかと話題のElixir。
達人プログラマやプログラミングRubyの著者で有名なDave Thomasさんが書いた
「Programming Elixir」で一気に知名度が上がりました。

Erlangの仮想環境上で動作するとか、並行処理が得意だとか、Ruby風味でとっつきやすいとか etc...
言語の特徴はすでにいろいろなサイト上で紹介されているので、あえてここでは触れません。
じっくり触ってみて、いずれ自分なりの見解を示したいと思っています。

では、アウトプットとしてElixir製のWebFrameworkであるPhoenixを利用して、
RESTFulなWebAPIを実装してみたいと思います。

バージョン

  • MacOSX El Capitan(10.11.6)
  • VirtualBox(5.1.8)
  • Vagrant(1.8.7)
  • Ubuntu(16.04 Xenial Xerus)
  • PostgreSQL(9.6)
  • Erlang/OTP(19.2.3)
  • Elixir(1.4.1)
  • Phoenix(1.2.1)

1. 仮想環境構築

こちらを参考に環境を作っておいてください。

2. PostgreSQLをインストール

PhoenixはデフォルトのデータストアをPostgreSQLに指定しているので、
こちらを参考にインストールしておいてください。

3. Erlang/OTPをインストール

冒頭でも書いた通り、ElixirはErlangの仮想環境上で動作するので、まずはErlang本体をインストールします。
ちなみにOTPは Open Telecom Platform の略で、Erlangの標準ツール類とライブラリ群の集合体です。
Erlang自体は言語仕様そのもので、OTPが無いと何もできないとか。
ErlangのコンパイラとインタプリタはこのOTPに含まれています。
OTPについてはこちらに詳しく書かれているので一読してみてください。
日本語翻訳はここ

Erlangのdebパッケージをダウンロード

適当なディレクトリにdebパッケージをダウンロードしてください。

$ cd /var/tmp
$ wget https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb

パッケージの取り込み

$ sudo dpkg -i erlang-solutions_1.0_all.deb

パッケージのアップデート

$ sudo apt-get update

Erlangのインストール

$ sudo apt-get install esl-erlang

確認

$ which erl
/usr/bin/erl

4. Elixirをインストール

Elixirのdebパッケージもありますが、今後頻繁にバージョンアップされる事を考慮してexenvでインストールします。
Rubyにはrbenvというバージョン管理ツールがありますが、そのElixir版がexenvになります。

exenvのダウンロード

$ sudo -s
# git clone https://github.com/mururu/exenv.git /usr/local/exenv
# git clone https://github.com/mururu/elixir-build.git /usr/local/exenv/plugins/elixir-build

exenvのパスを設定

どのユーザーでもexenvコマンドが使えるようにします。

$ vim /etc/profile.d/exenv.sh
export EXENV_ROOT="/usr/local/exenv"
export PATH="$EXENV_ROOT/bin:$PATH"
eval "$(exenv init -)"

設定を有効にする

# exec $SHELL -l

インストール可能なElixirのバージョンを表示

# exenv install --list

Elixirのインストール

# exenv install 1.4.1

システム全体で使用するElixirのバージョンを指定する

# exenv global 1.4.1

コマンド群を配置

# exenv rehash

確認

# elixir -v
Erlang/OTP 19 [erts-8.2] [source-fbd2db2] [64-bit] [smp:2:2] [async-threads:10] [hipe] [kernel-poll:false]

Elixir 1.4.1

5. Elixir&Erlang向けパッケージ管理ライブラリとビルドツールのインストール

一旦rootから抜ける

# exit

一般ユーザーでのexenvを有効化

$ exec $SHELL -l
$ which exenv

hexのインストール

$ mix local.hex --force

--force で最新を持ってきます

rebarのインストール

$ mix local.rebar --force

バージョン確認

$ mix hex.info
Hex:    0.15.0
Elixir: 1.4.1
OTP:    19.2.3

Built with: Elixir 1.3.4 and OTP 18.3.4.4

6. Phoenixのインストール

インストール実行

$ mix archive.install https://github.com/phoenixframework/archives/raw/master/phoenix_new.ez

バージョン確認

$ mix phoenix.new -v
Phoenix v1.2.1

7. プロジェクトの作成

ここまできたらようやくPhoenixフレームワークでAPIを作成する準備が整います。
それではやってみましょう!

適当なプロジェクトディレクトリを作成し移動

$ sudo mkdir -p /var/webapp
$ sudo chown vagrant:vagrant /var/webapp
$ cd /var/webapp

プロジェクトの作成

今回はTODOを管理するAPIを作成したいと思います。
APIなのでレイアウトやフロント周りのビルドツールは必要ありません。
--no-brunchと--no-htmlオプションで除外しておきます。

$ mix phoenix.new todo_api --no-brunch --no-html

作成されたtodo_api配下に移動し中身を確認すると、
下記のような構成になっているはずです。

$ cd todo_api
$ ls -l
drwxrwxr-x  9 vagrant vagrant 4096 Feb  9 23:04 ./
drwxr-xr-x  4 vagrant vagrant 4096 Feb 13 22:52 ../
drwxrwxr-x  4 vagrant vagrant 4096 Feb  9 23:06 _build/
drwxrwxr-x  2 vagrant vagrant 4096 Feb  9 23:06 config/
drwxrwxr-x 19 vagrant vagrant 4096 Feb  9 23:04 deps/
-rw-rw-r--  1 vagrant vagrant  378 Feb  9 23:04 .gitignore
drwxrwxr-x  3 vagrant vagrant 4096 Feb  9 23:04 lib/
-rw-rw-r--  1 vagrant vagrant 1549 Feb  9 23:04 mix.exs
-rw-rw-r--  1 vagrant vagrant 3513 Feb  9 23:04 mix.lock
drwxrwxr-x  5 vagrant vagrant 4096 Feb  9 23:04 priv/
-rw-rw-r--  1 vagrant vagrant  693 Feb  9 23:04 README.md
drwxrwxr-x  7 vagrant vagrant 4096 Feb  9 23:04 test/
drwxrwxr-x  7 vagrant vagrant 4096 Feb  9 23:21 web/

8. DBのセットアップ

PhoenixはデフォルトのデータストアにPostgreSQLが指定されているので、
事前に作成したPostgresのDB情報をPhoenixのDB設定に反映します。

開発用

$ vim config/dev.exs
# Configure your database
config :todo_api, TodoApi.Repo,
  adapter: Ecto.Adapters.Postgres,
  username: "作成したユーザー名",
  password: "作成したユーザーのパスワード",
  database: "todo_api_dev",
  hostname: "localhost",
  pool_size: 10

テスト用

$ vim config/test.exs
# Configure your database
config :todo_api, TodoApi.Repo,
  adapter: Ecto.Adapters.Postgres,
  username: "作成したユーザー名",
  password: "作成したユーザーのパスワード",
  database: "todo_api_test",
  hostname: "localhost",
  pool_size: 10

下記のコマンドでDBを作成します。

$ mix ecto.create

テストを実行してみます。

$ mix test

問題なくテストが通りました。

Compiling 6 files (.ex)
.............

Finished in 0.9 seconds
13 tests, 0 failures

Randomized with seed 903290

9. APIの作成

Railsにはscaffoldというアプリケーションの基盤を作成するジェネレータがありますが、
Elixirにも同様の機能が存在します。
今回はそれを利用してAPIの基盤を作成してみます。

ちなみにTODOの管理対象は

  • TODOの内容
  • 完了フラグ

の2つだけを持つとてもシンプルなものにします。
また、レスポンスはJSONで返したいのでphoenix.gen.jsonを指定します。
(その他のジェネレータについては、mix --help | grep phoenix.gen で調べてみてください。)

$ mix phoenix.gen.json Todo todos description:string complete:boolean

ジェネレータを実行すると priv/repo/migrations/ 配下に後述するマイグレーションファイルが作成されます。
その他にもいろいろ作成されていますが説明は省きます。

* creating web/controllers/todo_controller.ex
* creating web/views/todo_view.ex
* creating test/controllers/todo_controller_test.exs
* creating web/views/changeset_view.ex
* creating web/models/todo.ex
* creating test/models/todo_test.exs
* creating priv/repo/migrations/20170214011354_create_todo.exs ← マイグレーションファイル

Add the resource to your api scope in web/router.ex:

    resources "/todos", TodoController, except: [:new, :edit]

Remember to update your repository by running migrations:

    $ mix ecto.migrate

メッセージの中に「resources "/todos", TodoController, except: [:new, :edit]」の1行を、
ルーターのscopeブロックに追記してくださいと書かれているので追記します。

10. ルーターの編集

$ vim web/router.ex
defmodule TodoApi.Router do
  use TodoApi.Web, :router

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/api", TodoApi do
    pipe_through :api

    ### ここに追記 ###
    resources "/todos", TodoController, except: [:new, :edit]
  end
end

11. マイグレーションの実行

マイグレーションとは、マイグレーションファイルというテーブル定義書のようなものから、
SQLを書く事なくテーブルを作成したりフィールドやインデックスを追加したり、
作成したものをロールバックさせたりする機能です。
Railsではお決まりの機能ですね。

$ mix ecto.migrate

マイグレーションを実行すると priv/repo/migrations/ 配下にマイグレーションファイルが作成されます。

$ ls -l priv/repo/migrations
-rw-rw-r-- 1 vagrant vagrant  244 Feb 14 10:13 20170214011354_create_todo.exs

12. APIの動作確認

ここまでできたらサーバーを起動し、アクセスしてみましょう。

サーバーの起動

下記のコマンドを実行するとErlang製のWebサーバー(Cowboy)が起動します。

$ mix phoenix.server
[info] Running TodoApi.Endpoint with Cowboy using http://localhost:4000

アクセスして確認

他のマシーンからアクセスしてレスポンスが返ってくれば成功です。

$ curl -X GET "http://192.168.xxx.xxx:4000/api/todos"
{"data":[]}

まだ、データが何も登録されていなので空のレスポンスが返ってきます。

Cowboyのログ

[info] GET /api/todos
[debug] Processing by TodoApi.TodoController.index/2
  Parameters: %{}
  Pipelines: [:api]
[debug] QUERY OK source="todos" db=1.1ms
SELECT t0."id", t0."description", t0."complete", t0."inserted_at", t0."updated_at" FROM "todos" AS t0 []
[info] Sent 200 in 99ms

ためしに何かTODOをPOSTしてみます。

$ curl "http://192.168.xxx.xxx:4000/api/todos" -X POST -d "todo[description]=掃除をする" -d "todo[complete]=false"
{"data":{"id":1,"description":"掃除をする","complete":false}}

$ curl "http://192.168.xxx.xxx:4000/api/todos" -X POST -d "todo[description]=買い物に行く" -d "todo[complete]=true"
{"data":{"id":2,"description":"買い物に行く","complete":true}}

$ curl "http://192.168.xxx.xxx:4000/api/todos" -X POST -d "todo[description]=勉強する" -d "todo[complete]=false"
{"data":{"id":2,"description":"勉強する","complete":false}}

再度GETしてみます

curl -X GET "http://localhost:4000/api/todos"
{"data":[{"id":1,"description":"掃除をする","complete":false},{"id":2,"description":"買い物に行く","complete":true},{"id":3,"description":"勉強する","complete":false}]}

問題なく投稿したTODOが取得できました!

PATCHやDELETEもできそうです。
詳しくは web/controllers/todo_controller.ex を覗いてみてください。

13. おわりに

環境のセットアップが少々煩雑な感じを受けますが、
普段からRailsを触っている人にとってはほぼ迷いなく導入できると思います。

また、今回はscaffoldで手っ取り早く作成したので、
Phoenix(Elixir)のコードには一切触れていません。

なので、今後は自動で生成されたコード類を読みながら、
より理解を深めていきたいと思っています。

10
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
19