【入門】Elixir + Phoenix + MySQL で API サーバ

# はじめに

僕は今までRuby（Rails）やPHPといった言語でWEBやゲームの開発をしてきたのですが、最近何か違うものに触りたいという思いでElixirを学び始めました。

そこで見つけたのが、 @koga1020 さんが書かれていた 『[Phoenix + Vue.js入門](https://qiita.com/koga1020/items/c02a0fd5ae11fb5da1e0)』という記事でした。

今回は、この記事を参考にAPIサーバを構築し、初心者の自分が分からなかったところをメモとして、この記事に残していこうと思います。


# 1. プロジェクト作成
```shell
$ mix phx.new example_api_server_with_vuejs --no-brunch --database mysql
```

### 🔰 僕が引っかかったポイント 🔰
作成したプロジェクトと参考サイトのプロジェクトでディレクトリ構成が違いました。

原因は`古いバージョンのPhoenixでプロジェクトを作成していたから`でした。

最初、僕は`$ mix phoenix.new`コマンドを使用していたのですが、これだとどうやら1.2系の形でプロジェクトが構成されるようです。
（1.2と1.3で変更された内容に関しては[こちらの記事](https://qiita.com/shufo/items/f0c85a100728a39dde13)を参考にしました。）

# 2. DB接続
プロジェクト作成時にオプションで`--database mysql`を指定しているので、
`config/dev.exs`の50行目が下記のようになっていると思います。

```elixir
# Configure your database
config :example_api_server_with_vuejs, ExampleApiServerWithVuejs.Repo,
  adapter: Ecto.Adapters.MySQL,
  username: "root",
  password: "",
  database: "example_api_server_with_vuejs_dev",
  hostname: "localhost",
  pool_size: 10
```

自分のMySQLの情報に合わせて書き直してあげましょう。

# 3. API作成
## 3-1. 雛形ファイル作成

下記コマンドにより、まずは雛形となるJSONレスポンス用のController, View, Contextを作成します。

```shell
$ mix phx.gen.json Blog Article articles title:string body:text
```
### 🔰 僕が引っかかったポイント1 🔰
参考サイトには`$ mix phx.gen.json`によりモデルを作成とあったので、モデル関連のファイルが作成されると思ったのですが、なにやらControllerやViewまで作成されている…

むむむ？と思い、`$ mix help`で調べてみると、下記のような説明がされていました。

> mix phx.gen.json       # Generates controller, views, and context for a JSON resource

なるほどなるほど、`$ mix phx.gen.json`はJSONレスポンス用のいろいろを作成してくれるコマンドだったんですね！すごい便利ですね！

### 🔰 僕が引っかかったポイント2 🔰
上記の引っかかったポイント1について調べるとき、[公式リファレンス](https://hexdocs.pm/mix/master/Mix.html)を見たのですが、目的のものが見つけられなかった。（僕の見方が悪い可能性 ”大”）

そんなときに役に立ったのが `$ mix help`コマンドでした。
このコマンドを使うと、mixで使用可能なコマンド一覧とそれぞれの簡単な説明を出してくれます。有能！

# 3-2. テーブル作成

前節のコマンド実行時にマイグレーションファイルも作られているので、下記コマンドでテーブルを作成します。

```
$ mix ecto.migrate
```

# 3-3. ルーティング設定

下記のとおりルーティングを設定。

```elixir:router.ex
defmodule ExampleApiServerWithVuejsWeb.Router do
  use ExampleApiServerWithVuejsWeb, :router

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
#    plug :protect_from_forgery
    plug :put_secure_browser_headers
  end

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

  scope "/", ExampleApiServerWithVuejsWeb do
    pipe_through :browser # Use the default browser stack

    get "/", PageController, :index
  end

  # Scopes for API
   scope "/api", ExampleApiServerWithVuejsWeb do
     pipe_through :api

     resources "/articles", ArticleController, except: [:new, :edit]
  end
end
```

- `scope "/api", HogeFoo do ~ end`という記述により、この`do ~ end`内で設定したルーティング（URL）には先頭に`/api`が追加されます。

- ルーティング設定では、`get "/", PageController, :index`のように各リソースに対してHTTPメソッドをひとつひとつ定義する方法もありますが、今回は`resources`によって`articles`に対して主要なHTTPメソッド（処理）を一気に定義してあげます。

Phoenixのコマンドでルーティングを確認すると下記のようになっていると思います。

```sh
$ mix phx.routes

   page_path  GET     /                  ExampleApiServerWithVuejsWeb.PageController :index
article_path  GET     /api/articles      ExampleApiServerWithVuejsWeb.ArticleController :index
article_path  GET     /api/articles/:id  ExampleApiServerWithVuejsWeb.ArticleController :show
article_path  POST    /api/articles      ExampleApiServerWithVuejsWeb.ArticleController :create
article_path  PATCH   /api/articles/:id  ExampleApiServerWithVuejsWeb.ArticleController :update
              PUT     /api/articles/:id  ExampleApiServerWithVuejsWeb.ArticleController :update
article_path  DELETE  /api/articles/:id  ExampleApiServerWithVuejsWeb.ArticleController :delete
```

### 🔰 僕が引っかかったポイント 🔰

参考サイトでは、`plug :protect_from_forgery`がコメントアウトされています。
これはなんでしょうか…。分からずでした。誰か教えてください！
（名前から察するに、何かしらの悪意ある偽装をprotectするものですね笑）

ただ、

```elixir

pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
#    plug :protect_from_forgery
    plug :put_secure_browser_headers
  end
```

この部分は

```elixir

scope "/", ExampleApiServerWithVuejsWeb do
    pipe_through :browser # Use the default browser stack

    get "/", PageController, :index
  end
```

こちらの`scope "/"`用に定義されたパイプラインなので、今回のAPIには一切関係ないです。

Pipelineに関しては[こちらの記事](https://qiita.com/dynamitecoolguy/items/aeded848cde25a871da1#%E3%83%91%E3%82%A4%E3%83%97%E3%83%A9%E3%82%A4%E3%83%B3)で、Plugに関しては[こちらの記事](https://elixirschool.com/ja/lessons/specifics/plug/)である程度理解できました。

# 4. テスト

方法はなんでもいいですが、`http://0.0.0.0:4000/api/articles`にGETリクエストを投げてみましょう。
（僕は[Postman](https://www.getpostman.com/)を利用しました）

下記のようなレスポンスがあればOKです。

```json
{
    "data": []
}
```

空レスポンスを見ていてもつまらないので、新しいArticleを追加してみましょう。

Articleを追加するには、`http://0.0.0.0:4000/api/articles`にPOSTリクエストを投げればOKです。

そのさいのBodyは以下のようにします。（JSON形式）

```json
{
    "article": {
    	"title": "テスト題目",
    	"body": "テスト本文"
    }
}
```

リクエストを投げると、以下のようなレスポンスが返ってきます。

```json
{
    "data": {
        "title": "テスト題目",
        "id": 1,
        "body": "テスト本文"
    }
}
```

では、ここでもう一度`http://0.0.0.0:4000/api/articles`にGETリクエストを投げてみましょう。

```json
{
    "data": [
        {
            "title": "テスト題目",
            "id": 1,
            "body": "テスト本文"
        }
    ]
}
```

先程のArticleが追加されてますね！

さらにArticleを追加してみて、GETリクエストを投げると、以下のようになります。

```json

{
    "data": [
        {
            "title": "テスト題目",
            "id": 1,
            "body": "テスト本文"
        },
        {
            "title": "テスト題目2",
            "id": 2,
            "body": "テスト本文2"
        },
        {
            "title": "テスト題目3",
            "id": 3,
            "body": "テスト本文3"
        }
    ]
}
```

OKOK！
これで、Elixir + Phoenix + MySQL でAPIサーバができました。
簡単でしたね！

# おわりに 

ElixirはRailsのコアコミッターであるJose Valimさんによって作られているため、Rails経験者の僕にはすんなりと入門できました。

ただ、今回はコマンドで生成したコントローラで全てやってしまっています。
本来であれば、DDDのコンテキストという概念を取り入れた処理の書き方などがあるそうです。
Elixir + Phoenixをやっていく上では、そこも学んでいかないと思っています。

今後もがんばっていきます！


参考サイトでは、ここからVue.jsを使ったフロント側の実装に入りますが、そこはまた別記事で書きます。（多分…）

追記（2018/11/18）：
[個人ブログ](https://yyh-gl.hatenablog.com)始めました。
よかったらこちらもどうぞ！