argonautでjsonを扱う

# <i class="fa fa-bookmark-o" style="font-size:1em;"></i> argonaut とは

http://argonaut.io/

scalazにガンガン依存したものらしい。

# <i class="fa fa-cogs" style="font-size:1em;"></i> 設定

```scala
libraryDependencies ++= Seq(
  "io.argonaut" %% "argonaut" % "6.1-M5" exclude("org.scala-lang", "scala-compiler") changing(),
)
```
注意
>Note that the 6.0.x release supports scala 2.9.2, 2.9.3, 2.10.* and 2.11.0-RC1 with scalaz 7.0.*.
>Note that the 6.1.x development stream supports scala 2.10.* with scalaz 7.1.*. 


# <i class="fa fa-comment-o" style="font-size:1em;"></i> メモ
Decodeする際には型が合っていないと上手くいかない。
どこがどうあってないかは特にエラーで出してくれたりとかしてくれない。（してくれるかもしれないが、やり方がわからない）

# <i class="fa fa-code" style="font-size:1em;"></i> Encode

## <i class="fa fa-code" style="font-size:1em;"></i> Encodeしたいjson
```json:data
{
    "filters": null, 
    "from": null, 
    "issue": "issue", 
    "join": [
        "cmsid", 
        "title"
    ], 
    "order": null, 
    "query": "高垣彩陽", 
    "search": [
        "title", 
        "description", 
        "tags"
    ], 
    "service": [
        "video"
    ], 
    "size": null, 
    "sort_by": null
}
```


## <i class="fa fa-code" style="font-size:1em;"></i> Queryを定義
```scala:Query
package core.input

/**
 * Created by FScoward on 2015/01/11.
 */

import argonaut.Argonaut._
import argonaut.EncodeJson

case class Query(query: String,
                  service: List[Service],
                  search: Search,
                  join: List[Join],
                  filters: Option[List[Filter]],
                  sort_by: Option[String],
                  order: Option[String],
                  from: Option[Int],
                  size: Option[Int],
                  issue: String)

object Query{
  implicit def QueryEncodeJson: EncodeJson[Query] =
    Argonaut.jencode10L(Function.unlift(unapply))(
      "query", "service", "search", "join", "filters", "sort_by", "order", "from", "size", "issue"
    )
}

```

## <i class="fa fa-code" style="font-size:1em;"></i> Serviceの定義
```scala:Service
package core.input

/**
 * Created by FScoward on 2015/01/11.
 */

import argonaut.Argonaut._
import argonaut.EncodeJson

trait Search
sealed case class Keyword(val title: String = "title", val description: String = "description", val tags: String = "tags") extends Search
sealed case class Tag(val tags_exact: String = "tags_exact") extends Search
object Search {
  implicit def SearchEncodeJson: EncodeJson[Search] = {
    EncodeJson((search: Search) => search match {
      case keyword: Keyword => keyword.title.asJson -->>: keyword.description.asJson -->>: keyword.tags.asJson -->>: jEmptyArray
      case tag: Tag => tag.tags_exact.asJson -->>: jEmptyArray
    })
  }
}
```

## <i class="fa fa-code" style="font-size:1em;"></i> Join の定義
```scala:Join
package core.input

/**
 * Created by FScoward on 2015/01/11.
 */

import argonaut.Argonaut._
import argonaut.EncodeJson

/**
 * http://xerial.org/scala-cookbook/recipes/2012/06/29/enumeration/
 * */
sealed abstract class Join
object Join {
  case object cmsid extends Join
  case object title extends Join
  case object description extends Join
  case object tags extends Join
  case object start_time extends Join
  case object thumbnail_url extends Join
  case object view_counter extends Join
  case object comment_counter extends Join
  case object mylist_counter extends Join
  case object last_res_body extends Join
  case object length_seconds extends Join
  
  implicit def JoinValueEncodeJson: EncodeJson[Join] = {
    EncodeJson((jv: Join) => jString(jv.toString))
  }
}
```

## <i class="fa fa-code" style="font-size:1em;"></i> Filterの定義
```scala:Filter
package core.input

import argonaut.Argonaut._
import argonaut.EncodeJson

/**
 * Created by FScoward on 2015/01/11.
 */

case class Filter(`type`: String,
                  field: String,
                  value: Option[String] = None,
                  from: Option[String] = None,
                  to: Option[String] = None,
                  include_lower: Option[Boolean] = None,
                  include_upper: Option[Boolean] = None)
object Filter {
  implicit def FilterEncodeJson: EncodeJson[Filter] =
    jencode7L(Function.unlift(unapply))(
      "type", "field", "value", "from", "to", "include_lower", "include_upper"
    )
}
```

## <i class="fa fa-star-o" style="font-size:1em;"></i> 使ってみる

以下のようにやると、上記したjsonになる。

```scala
Query("高垣彩陽", List(Service.video), Keyword(), List(Join.cmsid, Join.title), None, None, None, None, None, "issue").jencode.nospaces
```



# <i class="fa fa-code" style="font-size:1em;"></i> Decode

## <i class="fa fa-code" style="font-size:1em;"></i> Decodeしたいjson

```json
{"dqnid":"5300db54-2c94-4ef7-a2e3-6250d40e3dcb",
"type":"hits",
"values":[
  {"_rowid":0,"cmsid":"sm16091596","title":"高垣彩陽「melodia」CM"},
  {"_rowid":1,"cmsid":"sm16658710","title":"高垣彩陽「Meteor Light」CM"},
  {"_rowid":2,"cmsid":"sm11708199","title":"高垣彩陽で「HOT  LIMIT」"},
  {"_rowid":3,"cmsid":"sm18218163","title":"Defying Gravity　高垣彩陽　Acoustic Guitar Instrumental②"},
  {"_rowid":4,"cmsid":"sm25090278","title":"3 leaf clover 高垣彩陽 Acoustic Guitar Instrumental"},
  {"_rowid":5,"cmsid":"sm18113692","title":"Defying Gravity　高垣彩陽　Acoustic Guitar Instrumental"},
  {"_rowid":6,"cmsid":"sm16987956","title":"【CM】「Meteor Light」高垣彩陽"},
  {"_rowid":7,"cmsid":"sm17238022","title":"高垣彩陽　1歳9ヶ月のときの声"},
  {"_rowid":8,"cmsid":"sm12584621","title":"高垣彩陽さんをまとめたみた。　Part 4"},
  {"_rowid":9,"cmsid":"sm6765149","title":"高垣彩陽＠ルチャーさん　前半"}]
}
```

## <i class="fa fa-code" style="font-size:1em;"></i> Result の定義
```scala:Result
package core.output

import argonaut.Argonaut._
import argonaut._

/**
 * Created by FScoward on 2015/01/11.
 */
case class Result(dqnid: String, `type`: String, values: Option[List[core.output.Value]], endofstream: Option[String])
object Result {
  implicit def ResultCodecJson: CodecJson[Result] = {
    casecodec4(Result.apply, Result.unapply)("dqnid", "type", "values", "endofstream")
  }
}
```

## <i class="fa fa-code" style="font-size:1em;"></i> Value の定義
```scala:Value
package core.output

/**
 * Created by FScoward on 2015/01/11.
 */
import argonaut.Argonaut._
import argonaut._
import core.input.Service

case class Value(_rowid: Int, cmsid: String, title: String, view_counter: Option[Int])
object Value {
  implicit def ValueCodecJson: CodecJson[Value] = {
    casecodec4(Value.apply, Value.unapply)("_rowid", "cmsid", "title", "view_counter")
  }
}
```

## <i class="fa fa-star-o" style="font-size:1em;"></i> 使ってみる

```scala
 json.decodeOption[Result] // jsonは上記したDecodeしたいjsonをStringで定義したもの

// 結果
Some(Result(5300db54-2c94-4ef7-a2e3-6250d40e3dcb,hits,Some(List(Value(0,sm16091596,高垣彩陽「melodia」CM,None), Value(1,sm16658710,高垣彩陽「Meteor Light」CM,None), Value(2,sm11708199,高垣彩陽で「HOT  LIMIT」,None), Value(3,sm18218163,Defying Gravity　高垣彩陽　Acoustic Guitar Instrumental②,None), Value(4,sm25090278,3 leaf clover 高垣彩陽 Acoustic Guitar Instrumental,None), Value(5,sm18113692,Defying Gravity　高垣彩陽　Acoustic Guitar Instrumental,None), Value(6,sm16987956,【CM】「Meteor Light」高垣彩陽,None), Value(7,sm17238022,高垣彩陽　1歳9ヶ月のときの声,None), Value(8,sm12584621,高垣彩陽さんをまとめたみた。　Part 4,None), Value(9,sm6765149,高垣彩陽＠ルチャーさん　前半,None))),None))
```

# <i class="fa fa-book" style="font-size:1em;"></i> 終わりに
試行錯誤しながら作ったので、コードが汚い

# <i class="fa fa-bullhorn" style="font-size:1em;"></i> 全容
https://github.com/FScoward/Niconico4s