sinatraでmbaasのモックサーバーを作ってテストする

URLを書き換えたりしたのでcurlサンプルはあてにしないほうがいい
rubyもobjective-cも初心者なのでわかったことがあったら随時追記していきます!

## sinatraって

rubyの軽量フレームワーク
rubyをベースに簡単にAPIサーバーが書けてしまう

## なんでsinatra?

- 簡単にmbaas連携のクライアント側をテストしたかった
- 実際のリクエストは飛ばしたくない(リクエスト数で課金していたりするので)
- sinatraで書いておけばiosもandroidも関係ないよね！
 - 自分はiOSから試してみた

## sinatraのインストール

```
$gem install sinatra
```

## sinatraの実装

```ruby
require 'sinatra'
require 'json'

# APIの定義
get '/test/:name' do
    name = params[:name]
end
```

基本は

- sinatraのrequireを忘れない
- get, post, put, deleteで受け付けるリクエストを定義する
 - :nameのように:変数名と書けばメソッド内部でパラメータとして使える
- レスポンスとして返却するのは、「最後に評価された変数」らしい

これだけでとりあえずOK
スクリプトを実行するとWEBサーバがローカルで立ち上がる

```
$ruby app.rb
```

この状態でcurlコマンドを実行してみます。

```
$ curl 'http://localhost:4567/test/hello'
hello
```

スクリプトに書いたとおり、nameの部分(=hello)が返ってきた

## Xcodeの設定

- ビルド設定によってエンドポイントが変わるようにする
- [O'Reillyのいい記事](http://www.oreilly.co.jp/community/blog/2014/05/scheme-and-build-settings-in-ios-development.html)

ざっくり書いていくと

- プロジェクトの設定を開いてInfoタブのConfigurationsを見る
- 新規にビルド設定を追加するときは既存の設定を真似ることができる
 - それしかできない
 - それしかできなくていいけど
- Build Settingsのタブに移って、Apple LLVM 6.0 - Preprocessingを開く
 - Preprocessor Macrosの部分で、ビルド設定ごとのマクロ定数を定義できる
 - 追加したビルド設定の時のみTEST=1という定数が使えるようにする

## iOS側の実装

新規にクラスを作成してマクロによって定数の中身を変えられるようにする

```objective-c
#ifdef TEST
#define URL @"http://localhost:4567"
#else
#define URL @"http://honban.api.com"
#endif
```

ローカルのエンドポイントにアクセスできるかをテストしてみる
(GHUnitを使っているけど、NSLogでもいいと思う)

```objective-c
/**
 localhostのエンドポイントにアクセスできるかのテスト
 */
- (void)test_accessToLocal_inDebugMode{
    NSURL *url =nil;
    url = [NSURL URLWithString:[NSString stringWithFormat:@"%@/test/hello",TEST_URL]];
    NSURLRequest *req = [NSURLRequest requestWithURL:url
                                         cachePolicy:NSURLRequestReloadIgnoringCacheData
                                     timeoutInterval:10.0];
    //req.HTTPMethod = @"GET";
    NSURLResponse *response = nil;
    NSError *error = nil;
    NSData *data = [NSURLConnection sendSynchronousRequest:req
                          returningResponse:&response
                                      error:&error];
    GHAssertNotNil(response, @"res:%@", response);
    GHAssertNotNil(data, nil);
    GHTestLog(@"res:%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}
```

シミュレーターで実行してみるとテストが通ってlocalhostからのレスポンスを取得できた!

## getリクエストのクエリストリングを受け取る

スクリプトを以下のように書き換えて、paramに何が入ってくるか試す

```ruby
require 'sinatra'
require 'json'

# paramに何が入るか試す
get '/:test' do
    params.to_json
end
```

curlでの実行結果は以下の通り

```
$ curl 'http://localhost:4567/test?param="{\"key\":\"value\"}"'
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<HTML>
  <HEAD><TITLE>Bad Request</TITLE></HEAD>
  <BODY>
    <H1>Bad Request</H1>
    bad URI `/test?param=&quot;&quot;key&quot;:&quot;value&quot;&quot;'.
    <HR>
    <ADDRESS>
     WEBrick/1.3.1 (Ruby/2.1.2/2014-05-08) at
     xxxx.local:4567
    </ADDRESS>
  </BODY>
</HTML>

$ curl 'http://localhost:4567/test?param%3d%22%7b%5c%22key%5c%22%3a%5c%22value%5c%22%7d%22'
{"param=\"{\\\"key\\\":\\\"value\\\"}\"":null,"splat":[],"captures":["test"],"path":"test"}

$ curl 'http://localhost:4567/test?param=%22%7b%5c%22key%5c%22%3a%5c%22value%5c%22%7d%22'
{"param":"\"{\\\"key\\\":\\\"value\\\"}\"","splat":[],"captures":["test"],"path":"test"}

$ curl 'http://localhost:4567/test?param=%22%7b%22key%22%3a%22value%22%7d%22'
{"param":"\"{\"key\":\"value\"}\"","splat":[],"captures":["test"],"path":"test"}
```

### わかったこと

- クエリストリングはURLエンコードしていないと受け取れない
 - =はエンコードしちゃいけない(キーとバリューがわからなくなる)

### ちょっとこまったこと

Mockサーバーはローカルのみの動作なのでビルド設定とschemeを増やした

- Debug
- Debug(TEST)
  - 実機でビルドする場合
- Debug(Mock)
  - シミュレータでビルドする場合
  - URLがローカルホストになる

schemeを増やしたら、Cocoa podsがうまく動かなかった
→pod updateをしたらなおった

## ステータスを変えてみたい

statusで変えられます
(簡単すぎる！すばらしすぎる！)

```ruby
require 'sinatra'
require 'json'

get '/test/:path' do
    if params["path"] != "hello"
        status 404
        "{'error':{'code': '404001', 'message':'no url'}}"
    else 
        params.to_json
    end 
end

```

## pod installしたライブラリ側でマクロを設定していた場合

- そのままビルドしてもマクロが動作してくれなかった
- Xcodeのworkspaceを開き、PodsプロジェクトのPod-YOUR_APP_TARGET-USE_LIB_NAMEのbuild settingsを開く
- 同じようにモック用のビルド設定用にマクロ定数を設定する

<del>これでビルドすればOK</del>

### OKじゃなかった

- 手動で設定するとPods/配下のXcodeプロジェクトファイルにマクロ定数が定義されるからgitで管理できない
- Pods/配下はignore指定している
- [ここ](http://odoruinu.net/blog/2014/01/01/how-to-define-preprocessor-macro-in-podfile-for-cocoapods/)を読んだ
- Podfileにpodがインストールされたあとの動作を追加
 - 上のブログ記事からほぼコピペでした
 - POD_TARGET_NAMEだけ先にXcodeで確認しておく必要があった