Play 2.5に入門　 ⑥コレクション指向のRESTフレームワークPlay'R

#Play'R v0.4
今回は、Play Scala 2.5で書かれているコレクション指向(?)のRESTフレームワークPlay'Rを試す。
https://github.com/26lights/PlayR

バージョンはまだ0.4と若いが、解説サイトが用意されている。
http://playr.26lights.com/index.html

使い方はシンプルで好感が持てる。


#例題を試す。
github側にかかれて通りように、sbtベースで動かす(compile/run)。
随時更新のようなので、動かないよ、とか怒られた時は、自ら直す。
サンプルのコードは短く見通しは良い。

##①playr-demo

コードは、
app/controller/PersonController.scala
のみのシンプルな例題。
Play'Rでは、以下のように書かれたPersonsをREST APIを介し公開できる。

```scala
case class Person(name: String)

@ImplementedBy(classOf[Persons])
trait PersonList {
  val persons: Map[Int, Person]
}

class Persons extends PersonList{
  val persons = Map(
    1 -> Person("john"),
    2 -> Person("jane")
  )
}
```


公開は、PlayのController経由にPlay'RのResource系traitを付したコントローラーで行う。

```scala
case class PersonController(personList: PersonList) extends Controller
                                                       with Resource[Person]
                                                       with ResourceRead
                                                       with ResourceList {
  def name = "person"

  implicit val personFormat = Json.format[Person]

  val persons = personList.persons

  def fromId(sid: String): Option[Person] = toInt(sid).flatMap(persons.get(_))

  def read(person: Person) = Action { Ok(Json.toJson(person)) }

  def list() = Action { Ok(Json.toJson(persons.keys)) }
}

class PersonRouter @Inject() (personList: PersonList) extends RestResourceRouter(PersonController(personList)) with ApiInfo {

  Logger.debug(s"Router instance created with person list: $personList")
}
```

解説は以下にある。
http://playr.26lights.com/demo.html

デバックモードで起動(sbt run)している時、コレクションを例えば以下のように更新すると、

```scala
class Persons extends PersonList{
  val persons = Map(
    1 -> Person("john"),
    2 -> Person("jane"),
    3 -> Person("石川五右衛門")

  )
}
```

更新がPersonRouterに伝えられ、Logger.debugが走る。
curlでアクセスしてみる:
> curl -f http://localhost:9000/person
[1,2,3]
> curl -f http://localhost:9000/person/3
{"name":"石川五右衛門"}

Personクラスの定義を変更すると、

```scala

case class Person(name: String,age:Int)

@ImplementedBy(classOf[Persons])
trait PersonList {
  val persons: Map[Int, Person]
}

class Persons extends PersonList{
  val persons = Map(
    1 -> Person("john",10),
    2 -> Person("jane",22),
    3 -> Person("石川五右衛門",34)

  )
}
```

即反映される。
> curl -f http://localhost:9000/person/3
{"name":"石川五右衛門","age":34}

##②playr-tutorial

こちらは少し複雑になっているので、[チュートリアル文書](http://playr.26lights.com/tutorial/intro.html)を読みながら試すのが良さそう。

conf/routesは、以下の定義のみ。

```
# Routes
# This file defines all application routes (Higher priority routes first)
# ~~~~

->      /api                        controllers.Application

GET     /*file                      controllers.Assets.at(path="/public", file)
```

sbt runした後、ついつい/apiにアクセスしたくなるが、404となる。

>curl -f http://localhost:9000/api
curl: (22) The requested URL returned error: 404 Not Found

Play'Rでは、上のroutesの定義は、
/api以下のアクセスは、controllers.Applicationがコントロールすると読むのが正しい。

参考　[Tutorial project structure](http://playr.26lights.com/tutorial/structure.html)

app/controller/Application.scalaを見てみる。

```Application.scala
class Application @Inject()(val cache: CacheApi, crmApi: CrmApi) extends PlayRRouter with PlayRInfo {

  implicit val colorContainer = ColorContainer(cache)

  val api = RootApiRouter()
    .add(new ColorController)
    .add(crmApi)
    .add(EnumValuesController(DaysEnum))
    .withFilter(LoggingFilter)

  val info = Map(
    "info" -> ApiInfo,
    "jquery.js" -> JQueryApi
  )
}
```

RESTインターフェースを

>  val api = RootApiRouter().add(new ColorController).add(crmApi)...

といった具合に追加していくものらしい。

いろいろとアクセスを試してみる。以下、わかりやすさからhttpieを用いる

参考　[curlを捨ててhttpieを使おう](http://qiita.com/yuku_t/items/5df06d50c4c349cc0c1b)　#curlは捨てなくて良いが..

```
> http GET localhost:9000/api/color   
HTTP/1.1 200 OK
Content-Length: 9
Content-Type: application/json
Date: Sat, 30 Apr 2016 03:49:56 GMT

[
    1,
    2,
    3,
    4
]

```

POSTしてみる。

あれ?　
ヘッダーのパラメータに入れても :
>http -v POST localhost:9000/api/color name:fakePurple rbg:#123456

JSONで送っても :
>http -v POST localhost:9000/api/color name=fakePurple rbg=#123456

エラーになる。

DELETEはできた:

![delete.PNG](https://qiita-image-store.s3.amazonaws.com/0/16455/70e347ef-129b-26c5-2685-0e7d29d67a20.png)


このあたりはもう後で見直すこととしよう。。。

この例題では、**会社-職種-従業員 <-> Person**的な入れ子関係のRESTインターフェースも提供されている:

![company.PNG](https://qiita-image-store.s3.amazonaws.com/0/16455/f341336f-32ed-f6d8-bc6a-92e6cacbf0fc.png)

こちらはweb DB的なものを作る時に参考になりそう。

###jquery.scala.jsも
アクセス方法がわからなかったが、scala.jsも使われている模様。

#感想

今回は、ちら見しただけだが、Scala使いな人が、さくっとPlay scalaでRESTしたい時には良いのかも。

[前回見たBaasBox](http://qiita.com/kmry2045/items/11575702a2943c559f67)はPlay2.2でがっつり書かれたRESTなmBaaS。BaasBoxそのものの改造/改良は大変な感じ...、なので、このPlay'Rに、BaasBoxのRESTインターフェースを移してのは学習として良いかも！？