Rack::JsonSchemaのspecupを利用してJSON Schemaを元にダミーレスポンスサーバーを起動します

@r7kamuraさん作のRack::JsonSchemaのspecupを利用して
JSON Schemaを元にダミーレスポンスサーバーを起動します

## <i class="fa fa-check-circle" style="font-size:1em;"></i> 準備
Rack::JsonSchemaについては@r7kamuraさん本人による下記のエントリをチェック

<i class="fa fa-external-link" style="font-size:1em;"></i> [全てがJSONになる](http://r7kamura.hatenablog.com/entry/2014/06/10/023433)

## <i class="fa fa-flask" style="font-size:1em;"></i> サンプル
* あらかじめ rack-json_schema gem をインストールしておきます

### <i class="fa fa-file-text" style="font-size:1em;"></i> JSON Schema

~~~json:schema.json
{
  "description": "このスキーマ定義では、Sample API v1 のインターフェースをJSON Hyper Schema draft v4形式で表現しています。",
  "links": [
    {
      "method": "GET",
      "title": "{:href=>\"http://localhost:3000\", :rel=>\"self\"}"
    }
  ],
  "properties": {
    "people": {
      "links": [
        {
          "description": "全ての人物の一覧を取得します。",
          "href": "/api/v1/people",
          "method": "GET",
          "rel": "instances",
          "title": "list"
        },
        {
          "description": "人物を取得します。",
          "href": "/api/v1/people/:id",
          "method": "GET",
          "rel": "self",
          "title": "get"
        },
        {
          "description": "人物を登録します。",
          "href": "/api/v1/people/:id",
          "method": "POST",
          "rel": "self",
          "schema": {
            "properties": {
              "name": {
                "description": "人物の名前",
                "example": "tanaka",
                "type": "string"
              },
              "age": {
                "description": "人物の年齢",
                "example": 34,
                "type": "integer"
              }
            },
            "required": [
              "name",
              "age"
            ]
          },
          "title": "create"
        },
        {
          "description": "人物を更新します。",
          "href": "/api/v1/people/:id",
          "method": "PATCH",
          "rel": "self",
          "schema": {
            "properties": {
              "name": {
                "description": "人物の名前",
                "example": "tanaka",
                "type": "string"
              },
              "age": {
                "description": "人物の年齢",
                "example": 34,
                "type": "integer"
              }
            },
            "required": [
              "name",
              "age"
            ]
          },
          "title": "update"
        },
        {
          "description": "人物を削除します。",
          "href": "/api/v1/people/:id",
          "method": "DELETE",
          "rel": "self",
          "title": "delete"
        }
      ],
      "properties": {
        "id": {
          "description": "人物のid",
          "example": 1,
          "type": "integer"
        },
        "name": {
          "description": "人物の名前",
          "example": "tanaka",
          "type": "string"
        },
        "age": {
          "description": "人物の年齢",
          "example": 34,
          "type": "integer"
        }
      },
      "required": [
        "id",
        "name",
        "age"
      ],
      "title": "Person"
    }
  },
  "required": [
    "people"
  ],
  "title": "Sample API v1 JSON Schema"
}
~~~

## <i class="fa fa-child" style="font-size:1em;"></i> 動作確認
### <i class="fa fa-server" style="font-size:1em;"></i> specup
specupでダミーレスポンスサーバーを起動します

~~~bash
$ specup schema.json
[2015-08-05 04:54:09] INFO  WEBrick 1.3.1
[2015-08-05 04:54:09] INFO  ruby 2.2.0 (2014-12-25) [x86_64-linux]
[2015-08-05 04:54:09] INFO  WEBrick::HTTPServer#start: pid=2041 port=8080
~~~

### <i class="fa fa-file-text" style="font-size:1em;"></i> Schema
~~~bash
$ curl -X GET http://localhost:8080/schema
# json schemaが出力される
~~~

### <i class="fa fa-book" style="font-size:1em;"></i> Docs
~~~bash
$ curl -X GET http://localhost:8080/docs
# HTML形式のSchemaドキュメントが出力される
~~~

### <i class="fa fa-users" style="font-size:1em;"></i> リスト参照
~~~bash
$ curl -X GET http://localhost:8080/api/v1/people
[
  {
    "id": 1,
    "name": "tanaka",
    "age": 34
  }
]
~~~

### <i class="fa fa-user" style="font-size:1em;"></i> 1件参照
~~~bash
$ curl -X GET http://localhost:8080/api/v1/people/1
{
  "id": 1,
  "name": "tanaka",
  "age": 34
}
~~~

### <i class="fa fa-plus-circle" style="font-size:1em;"></i> 登録
~~~bash
$ curl -X GET http://localhost:8080/api/v1/people/1
{
  "id": 1,
  "name": "tanaka",
  "age": 34
}
~~~

### <i class="fa fa-refresh" style="font-size:1em;"></i> 更新
~~~bash
$ curl -X PATCH -H "Content-Type: application/json" -d \
'{"name":"hoge_update", "age": 12345}' http://localhost:8080/api/v1/people/1
{
  "id": 1,
  "name": "tanaka",
  "age": 34
}
~~~

* わざと不正データを送る: age を文字列にする

~~~bash
$ curl -X PATCH -H "Content-Type: application/json" -d \
'{"name":"hoge_update", "age": "12345"}' http://localhost:8080/api/v1/people/1
{
  "id": "invalid_parameter",
  "message": "Invalid request.\n#/age: failed schema #/properties/person/links/3/schema/properties/age: \"12345\" is not a integer."
}
~~~

* わざと不正データを送る: age なし

~~~bash
$ curl -X PATCH -H "Content-Type: application/json" -d \
'{"name":"hoge_update"}' http://localhost:8080/api/v1/people/1
{
  "id": "invalid_parameter",
  "message": "Invalid request.\n#: failed schema #/properties/person/links/3/schema: \"age\" wasn't supplied."
}
~~~

### <i class="fa fa-trash" style="font-size:1em;"></i> 削除
~~~bash
$ curl -X DELETE http://localhost:8080/api/v1/people/7
{
  "id": 1,
  "name": "tanaka",
  "age": 34
}
~~~

### <i class="fa fa-warning" style="font-size:1em;"></i> 不正リンク
linksで定義していないリクエストを送る

~~~bash
$ curl -X GET http://localhost:8080/api/v1/hoge/
{
  "id": "link_not_found",
  "message": "Could not find the link definition for request path /api/v1/hoge/."
}
~~~

## <i class="fa fa-book" style="font-size:1em;"></i> 関連エントリ
* <i class="fa fa-external-link-square" style="font-size:1em;"></i> [JsonWorldを利用してJSON SchemaとJSONを生成してみる](http://qiita.com/tbpgr/items/664a5038797e0f50d6ef)
* <i class="fa fa-external-link-square" style="font-size:1em;"></i> [JsonWorldを利用して生成したJSON Schemaを読み込み、JsonismでAPIを呼び出す](http://qiita.com/tbpgr/items/d7b96fe3dc9cb0e44c5c)

## <i class="fa fa-book" style="font-size:1em;"></i> 外部資料
* <i class="fa fa-external-link" style="font-size:1em;"></i> [Rack::JsonSchema - GitHub](https://github.com/r7kamura/rack-json_schema)
* <i class="fa fa-external-link" style="font-size:1em;"></i> [全てがJSONになる](http://r7kamura.hatenablog.com/entry/2014/06/10/023433)