Erlang, AngularJSアプリケーション


ソースコードは下の[ここ](https://github.com/ColdFreak/try_cowboy)にあります

RebarでErlang/OPTアプリケーションのリリースを作成したい場合は[前の投稿](http://qiita.com/ColdFreak/items/e43d91eda5e8a3f39c46)を参照してください．この文書はerlang.mkでErlang/OPTアプリケーションのリリースを作成します．例としてはCowboyでPostリクエストを処理するプログラムを書きます．イメージとしては文書の最後の部分を参照してください．ソースコードは[cowboyのexample](https://github.com/ninenines/cowboy/tree/master/examples/echo_post)をベースにしたものです．


### erlang.mkをダウンロード

まずディレクトリcowboy_postを作成して，erlang.mkファイルをダウンドードします．

```
$ mkdir cowboy_post
$ cd cowboy_post
$ curl -O https://raw.githubusercontent.com/ninenines/erlang.mk/master/erlang.mk
```

### プロジェクトを作成

必要なファイルを作成するためにBootstrapします．Makefileも下のコマンドで作成されます．

```
$ make -f erlang.mk bootstrap bootstrap-rel
$ tree -L 2
.
├── Makefile
├── erlang.mk
├── rel
│   ├── sys.config
│   └── vm.args
├── relx.config
└── src
    ├── cowboy_post.app.src
    ├── cowboy_post_app.erl
    └── cowboy_post_sup.erl

2 directories, 8 files
```

### Makefileなど各ファイルを追加

cowobyが必要のため，Makefileに依存パッケージ(DEPS)に cowboyを追加します．

注意：Makefileにcowboyのリンクを付け加えないと古いcowboyをとってきますので，古い書き方(init/3)だと下のtoppage_handlerのinit/2が通らないです．

```
$ cat Makefile
PROJECT = cowboy_post
DEPS = cowboy
dep_cowboy = git https://github.com/ninenines/cowboy master
include erlang.mk
```

src/cowboy_post.app.srcファイルにもcowboyを追加します．

```
$ cat src/cowboy_post.app.src
{application, cowboy_post, [
	{description, ""},
	{vsn, "0.1.0"},
	{id, "git"},
	{modules, []},
	{registered, []},
	{applications, [
		kernel,
		stdlib,
        cowboy
	]},
	{mod, {cowboy_post_app, []}},
	{env, []}
]}.
```

そして，一旦makeします

```
$ make
```

![Screen Shot 2015-02-07 at 10.15.53 AM.png](https://qiita-image-store.s3.amazonaws.com/0/54698/a42e2681-7d5d-865e-1249-07fff16cb8a1.png)


次はpriv/static/index.htmlファイルを用意します．

```
$ mkdir -p priv/static
$ cd priv/static
$ touch index.html
```

index.htmlファイルの中身は下のコードで，submitを押すと/processページで処理します

```html
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
    <form method="post" action="/process">
        <input type="text"  name="echo">
        <input type="submit" value="submit">
    </form>
</body>
</html>
```

src/cowboy_post_app.erlを下のように追加します．priv_fileに関する説明は[こちら](http://ninenines.eu/docs/en/cowboy/HEAD/guide/static_files/)にあります

```erlang
$ cat cowboy_post_app.erl
-module(cowboy_post_app).
-behaviour(application).

-export([start/2]).
-export([stop/1]).

start(_Type, _Args) ->
    Dispatch =  cowboy_router:compile([
        {'_', [
                {"/", cowboy_static, {priv_file, cowboy_post, "static/index.html" }},
                {"/process", toppage_handler, []}
              ]
        }
    ]),
    {ok, _} = cowboy:start_http(http, 100, [{port, 8080}], [
        {env, [{dispatch, Dispatch}]}
    ]),
	cowboy_post_sup:start_link().

stop(_State) ->
	ok.
```

上のstart関数のtoppage_handlerはハンドラのことで，ウェブページでsubmitすると，/processというルールを処理するのはtoppage_handler．なので，toppage_handler.erlファイルを追加します．

```
$ touch src/toppage_handler.erl
```

toppage_handler.erlファイルの中身

```erlang
$ cat 
%% Feel free to use, reuse and abuse the code in this file.

%% @doc POST toppage_handler.
-module(toppage_handler).

-export([init/2]).

init(Req, Opts) ->
	Method = cowboy_req:method(Req),
	HasBody = cowboy_req:has_body(Req),
	Req2 = maybe_echo(Method, HasBody, Req),
	{ok, Req2, Opts}.

maybe_echo(<<"POST">>, true, Req) ->
	{ok, PostVals, Req2} = cowboy_req:body_qs(Req),
	Echo = proplists:get_value(<<"echo">>, PostVals),
	echo(Echo, Req2);
maybe_echo(<<"POST">>, false, Req) ->
	cowboy_req:reply(400, [], <<"Missing body.">>, Req);
maybe_echo(_, _, Req) ->
	%% Method not allowed.
	cowboy_req:reply(405, Req).

echo(undefined, Req) ->
	cowboy_req:reply(400, [], <<"Missing echo parameter.">>, Req);
echo(Echo, Req) ->
	cowboy_req:reply(200, [
		{<<"content-type">>, <<"text/plain; charset=utf-8">>}
	], Echo, Req).
```

上のコードに注目すべき一つのところは 
`Echo = proplists:get_value(<<"echo">>, PostVals),`
ここの`<<"echo">>`はどこから来ているかというとindex.htmlファイルの`name="echo"` のinputタグから来ています．つまり`proplists:get_value/2`を使って，name属性echoのinputタグに入力した内容を取り出す．なぜ`<<"echo">>`なんでしょう？　Cowboyはbinary stringを使用しているからです．githubのページにも書いてあるように
> Cowboy aims to provide a complete HTTP stack in a small code base. It is optimized for low latency and low memory usage, in part because it uses binary strings.

src/cowboy_post_sup.erlファイルは特に修正は必要がないです．

再度makeしてから，アプリケーションを立ち上げます．
`$ _rel/cowboy_post_release/bin/cowboy_post_release console`
コマンドの中のconsoleの代わりにstart/stopも使えます．

```
$ make
$ _rel/cowboy_post_release/bin/cowboy_post_release console
Eshell V6.3  (abort with ^G)
(cowboy_post@127.0.0.1)1>
```

これで127.0.0.1:8080をアクセスできるようになっています．

![Screen Shot 2015-02-07 at 11.01.19 AM.png](https://qiita-image-store.s3.amazonaws.com/0/54698/01db7d54-e04a-d38e-70a2-4c1b69943e26.png)
![Screen Shot 2015-02-07 at 11.01.53 AM.png](https://qiita-image-store.s3.amazonaws.com/0/54698/ad80c800-4f31-2fa8-0491-b11fcbb31d63.png)


ここまでくるとcowboy_postディレクトリ下の構造は下のようになっています．

```
$ tree -L 2
.
├── Makefile
├── _rel
│   └── cowboy_post_release
├── deps
│   ├── cowboy
│   ├── cowlib
│   └── ranch
├── ebin
│   ├── cowboy_post.app
│   ├── cowboy_post_app.beam
│   ├── cowboy_post_sup.beam
│   └── toppage_handler.beam
├── erlang.mk
├── priv
│   └── static
├── rel
│   ├── sys.config
│   └── vm.args
├── relx
├── relx.config
└── src
    ├── cowboy_post.app.src
    ├── cowboy_post_app.erl
    ├── cowboy_post_sup.erl
    └── toppage_handler.erl
```

### AngularJSを使う

AngularJSを使うためにまず`angular.js`をダウンロード

```shell-session
$ mkdir -p priv/static/js
$ cd priv/static/js
$ wget https://ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular.js
```

`priv/static/angular.html`ファイルを追加します。中身は下のように追加します。

```html
 <!doctype html>
 <html>
    <head>
    <script src="/js/angular.js"></script>
    </head>
    <body ng-app="myapp">
       <div ng-controller="HelloController" >
          <h2>Welcome {{helloTo.title}} to the world of Tutorialspoint!</h2>
       </div>
       <script>
          angular.module("myapp", [])
          .controller("HelloController", function($scope) {
             $scope.helloTo = {};
             $scope.helloTo.title = "AngularJS";
          });
       </script>
    </body>
 </html>
```

htmlファイルに`<script src="/js/angular.js"></script>`を書き込んでもそのまま使えないです。

`src/cowboy_post_app.erl`ファイルに下の二行を追加します。

```
{"/app", cowboy_static, {priv_file, cowboy_post, "static/angular.html" }},
{"/js/[...]", cowboy_static, {priv_dir, cowboy_post, "static/js"}},
```

今は`cowboy_post_app.erl`ファイルは下のようになっています。

```erlang
-module(cowboy_post_app).
 -behaviour(application).

 -export([start/2]).
 -export([stop/1]).

 start(_Type, _Args) ->
     Dispatch =  cowboy_router:compile([
         {'_', [
                 {"/", cowboy_static, {priv_file, cowboy_post, "static/index.html" }},
                 {"/app", cowboy_static, {priv_file, cowboy_post, "static/angular.html" }},
                 {"/js/[...]", cowboy_static, {priv_dir, cowboy_post, "static/js"}},
                 {"/echo", echo_handler, []}
               ]
         }
     ]),
     {ok, _} = cowboy:start_http(http, 100, [{port, 3333}], [
         {env, [{dispatch, Dispatch}]}
     ]),
     cowboy_post_sup:start_link().

 stop(_State) ->
     ok.

```

上のコードの中の`/js/[...]`部分に関しては[このリンク](http://ninenines.eu/docs/en/cowboy/HEAD/guide/static_files/)を参照します。

`priv`ディレクトリ下の構造は

```
├── priv
│   └── static
│       ├── angular.html
│       ├── index.html
│       └── js
│           └── angular.js
```

アプリをコンパイルして、リスタートする

```shell-session
$ make
$ _rel/cowboy_post_release/bin/cowboy_post_release restart
```

![スクリーンショット 2015-07-14 20.18.56.png](https://qiita-image-store.s3.amazonaws.com/0/54698/338844f5-9cea-dc60-ea99-405516441d2d.png)