ElixirからCowboy 1.0と2.0を使ってみる Part 3

# はじめに
ElixirにてCowboyを直接動かすための記事となります。
[Cowboy1.0の前回](http://qiita.com/hayabusa333/items/50ae4d65f778654927cd)や[Cowboy2.0の前回](http://qiita.com/hayabusa333/items/2642af88f0eccee1c923)の記事では、cowboyにてHTMLページの表示を行いました。
今回はjsonを返すAPIのなりそこないの実装を行っていきます。
1.0と2.0の記事をまとめろっと外部からの声がありましたので、今回から記事をまとめていきたいと思います。

[Cowboy1.0のサンプルコードはこちらになります](https://github.com/hayabusa333/elixir_cowboy_example/tree/static_json_cowboy)

[Cowboy2.0のサンプルコードはこちらになります](https://github.com/hayabusa333/elixir_cowboy_example/tree/static_json_cowboy_two_pre4)

# バージョン
使用した言語やライブラリのバージョンは下記となります。

## cowboy 1.0のバージョン
|  | Version |
|:-----------|--------:|
| Elixir | 1.3.2 |
| Erlang | 19.2 |
| Cowboy | 1.0.4 |

## cowboy 2.0のバージョン
|  | Version |
|:-----------|--------:|
| Elixir | 1.3.2 |
| Erlang | 19.2 |
| Cowboy | 2.0.0-pre4 |

# 毎回同じJSONを返すAPIの作成

さて、まず実装するJSONのAPIですが、毎回同じ内容のJSONを返すAPIを作成していきます。
毎回同じ内容を返すAPIに何の意味があるのか？っという話もありますが、最初の最初として実装していきます。

## cowboy 1.0の場合

``` elixir:lib/elixir_cowboy_example/json_handler.ex
defmodule ElixirCowboyExample.JsonHandler do
  def init({:tcp, :http}, req, opts) do
    {:ok, req, opts}
  end

  def handle(req, state) do
    {method, req} = :cowboy_req.method(req)
    {:ok, req} = json_example(method, req)
    {:ok, req, state}
  end

  # bodyに "{\"title\": \"hello cowboy!\"}" を設定し、
  # jsonを返すようにheadersを設定
  def json_example("POST", req) do
    headers = [{"content-type", "application/json"}]
    body = "{\"title\": \"hello cowboy!\"}"
    {:ok, resp} = :cowboy_req.reply(200, headers, body, req)
  end

  def terminate(_reason, _req, _state) do
    :ok
  end
end
```

``` elixir:lib/elixir_cowboy_example.ex
  def run do
    # http://localhost:4000/json にアクセスした際に
    # jsonを返すようにHandlerの設定
    routes = [
      {"/", ElixirCowboyExample.Handler, []},
      {"/json", ElixirCowboyExample.JsonHandler, []},
      {"/:html", ElixirCowboyExample.Handler, []}
    ]

    dispatch = :cowboy_router.compile([{:_, routes}])

    opts = [port: 4000]
    env = [dispatch: dispatch]

    {:ok, _pid} = :cowboy.start_http(:http, 100, opts, [env: env])
  end
```

## cowboy 2.0の場合

``` elixir:lib/elixir_cowboy_example/json_handler.ex
defmodule ElixirCowboyExample.JsonHandler do
  def init(req, opts) do
    method = :cowboy_req.method(req)
    {:ok, resp} = json_example(method, req)
    {:ok, resp, opts}
  end

  # bodyに "{\"title\": \"hello cowboy!\"}" を設定し、
  # jsonを返すようにheadersを設定
  def json_example("POST", req) do
    headers = %{"content-type" => "application/json"}
    body = "{\"title\": \"hello cowboy!\"}"
    {:ok, resp} = :cowboy_req.reply(200, headers, body, req)
  end
end
```

``` elixir:lib/elixir_cowboy_example.ex
  def run do
    # http://localhost:4000/json にアクセスした際に
    # jsonを返すようにHandlerの設定
    routes = [
      {"/", ElixirCowboyExample.Handler, []},
      {"/json", ElixirCowboyExample.JsonHandler, []},
      {"/:html", ElixirCowboyExample.Handler, []}
    ]

    dispatch = :cowboy_router.compile([{:_, routes}])

    opts = [{:port, 4000}]
    env = %{dispatch: dispatch}

    {:ok, _pid} = :cowboy.start_clear(:http, 100, opts, %{env: env})
  end
```

# 記載したコードの実行
コードの記述が完了しましたので、それでは実行していきましょう。
いつも通り `iex -S mix` にて cowboy を実行していきます。
今回は、jsonを返すAPIですので、curlで実行していきます。

``` cmd
$ curl -v -H "Accept: application/json" -H "Content-type: application/json" -X POST http://localhost:4000/json
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 4000 (#0)
> POST /json HTTP/1.1
> Host: localhost:4000
> User-Agent: curl/7.43.0
> Accept: application/json
> Content-type: application/json
> Content-Length: 23
> 
* upload completely sent off: 23 out of 23 bytes
< HTTP/1.1 200 OK
< content-length: 26
< content-type: application/json
< date: Sat, 07 Jan 2017 06:59:11 GMT
< server: Cowboy
< 
* Connection #0 to host localhost left intact
{"title": "hello cowboy!"}
```

# 受け取ったパラメータからjsonを返す

毎回同じjsonを返すAPIには意味がないので、今回は受け取ったパラメータの内容をJson形式にて返すAPIを実装していきます。

今回の実装では受け取ったパラメータが複数あったとしても一番最初のものしか受け取りませんし、エラー処理も実際に使うためには必要ですが、パラメータの受け渡しをみるためなので、その辺りは気にせずいきます。

## cowboy 1.0の場合

``` elixir:lib/elixir_cowboy_example/json_handler.ex
defmodule ElixirCowboyExample.JsonHandler do
  def init({:tcp, :http}, req, opts) do
    {:ok, req, opts}
  end

  def handle(req, state) do
    {method, req} = :cowboy_req.method(req)
    # bodyの中のパラメータの情報を取得する
    {:ok, params, req} = :cowboy_req.body_qs(req)
    {:ok, req} = json_example(method, params, req)
    {:ok, req, state}
  end

  def json_example("POST", :undefined , req) do
    headers = [{"content-type", "application/json"}]
    body = "{\"title\": \"hello cowboy!\"}"
    {:ok, resp} = :cowboy_req.reply(200, headers, body, req)
  end

  def json_example("POST", params, req) do
    # 上記にて受け取ったパラメータはリストの中にtupleで入っているので
    # 情報の抜き出しをおこなう
    param = params |> Enum.at(0) |> elem(1)
    headers = [{"content-type", "application/json"}]
    body = "{\"title\": \"#{param}\"}"
    {:ok, resp} = :cowboy_req.reply(200, headers, body, req)
  end

  def terminate(_reason, _req, _state) do
    :ok
  end
end
```

## cowboy 2.0の場合

``` elixir:lib/elixir_cowboy_example/json_handler.ex
defmodule ElixirCowboyExample.JsonHandler do
  def init(req, opts) do
    method = :cowboy_req.method(req)
    # bodyの中のパラメータの情報を取得する
    # cowboy2.0 ではメソッド名が変わったもよう
    {ok, params, req} = :cowboy_req.read_urlencoded_body(req)
    {:ok, resp} = json_example(method, params, req)
    {:ok, resp, opts}
  end

  def json_example("POST", :undefined, req) do
    headers = %{"content-type" => "application/json"}
    body = "{\"title\": \"hello cowboy!\"}"
    {:ok, resp} = :cowboy_req.reply(200, headers, body, req)
  end

  def json_example("POST", params, req) do
    # 上記にて受け取ったパラメータはリストの中にtupleで入っているので
    # 情報の抜き出しをおこなう
    param = params |> Enum.at(0) |> elem(1)
    headers = %{"content-type" => "application/json"}
    body = "{\"title\": \"#{param}\"}"
    {:ok, resp} = :cowboy_req.reply(200, headers, body, req)
  end
end
```

# 記載したコードの実行

コードの記述が完了しましたので、それでは実行していきましょう。
上記で実行した`curl`に合わせて、-d オプションにて パラメータの受け渡しを実施します。
結果としてパラメータで渡した内容が返ってくることが見て取れます

``` cmd
$ curl -v -H "Accept: application/json" -H "Content-type: application/json" -X POST -d 'title=test1' http://localhost:4000/json
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 4000 (#0)
> POST /json HTTP/1.1
> Host: localhost:4000
> User-Agent: curl/7.43.0
> Accept: application/json
> Content-type: application/json
> Content-Length: 23
> 
* upload completely sent off: 23 out of 23 bytes
< HTTP/1.1 200 OK
< content-length: 18
< content-type: application/json
< date: Sun, 08 Jan 2017 00:18:26 GMT
< server: Cowboy
< 
* Connection #0 to host localhost left intact
{"title": "test1"}
```

# 最後に
JSONを返すAPIの実装をおこなうことができました。
受け取ったパラメータを処理することもできましたので、受け取ったパラメータの内容からEctoからデータベースにアクセスしてJSONを返すこともできるようになったのではないでしょうか？
その辺りを実際に行っていくのは次回以降のどこかで行えたら行っていきたいと考えております。
それではまた次回

# 参考サイト
[Cowboy User Guide](https://ninenines.eu/docs/en/cowboy/1.0/guide/)