Grails 3.1のJSON Viewsを触ってみた

これは[G* Advent Calendar 2015](http://qiita.com/advent-calendar/2015/gastah)の15日目の記事です。

今日はGrailsの次期バージョン 3.1の新機能であるJSON Viewsについて紹介してみます。この記事はGrails 3.1M3を元に書いていますので、リリース時には状況が変わっているかもしれませんが、そのへんはご了承を。

## はじめに

JSON Viewsとは、Grails ViewsにおけるJSON実装です。JSONのレンダリングにはGroovyのJsonBuilderが使われています。Grails ViewsはGrailsに新たなビューのサポートを追加する仕組みで、Grails 3.0まではビューと言えばGSP(Groovy Servers Pages)というHTMLをレンダリングするビューしか基本的には存在しませんでしたが、このGrails ViewsによってGSP以外の様々なビューのサポートを追加できるようになっています。

ちなみにJSON以外の現時点でのGrails Viewsの実装としては、GroovyのMarkupTemplateEngineを使ったMarkup Viewsがあります。

## プロジェクト準備

JSON Viewsをてっとり早く試してみるにはweb-apiプロファイルを使ってプロジェクトを作成します。

```
grails create-app sample-json-views --profile=web-api
```

プロファイルにweb-apiを指定することで、JSON Viewsに必要な依存関係がbuild.gradleに設定された形でプロジェクトが生成されます。生成されたbuild.gradleでJSON Viewsに関連する部分は以下です。

```
buildscript {
    ...
    dependencies {
        ...
        classpath "org.grails.plugins:views-gradle:1.0.0.RC2"
    }
}
...
apply plugin:"org.grails.plugins.views-json"
...
dependencies {
    ...
    compile "org.grails.plugins:views-json"
}
```

Gradleのプラグインを`buildscript`と`apply plugin:"org.grails.plugins.views-json"`が設定され、プロジェクトの依存関係に`"org.grails.plugins:views-json"`が追加されています。

## 基本的な使い方

とりあえず適当なコントローラを作成します。

```
class HelloController {

    def index() {
        [name: 'yamada']
    }
}
```

`name`というキーをもつモデルを単に返しています。GSPと同じでこのモデルがビューで参照できます。

ここでJSON Viewsのビューのファイルを作成します。ファイルはGSPと同じようにgrails-app/viewsディレクトリに格納します。ファイルの拡張子は`.gson`です。

ここではgrails-app/views/hello/index.gsonを次のように実装します。

```
model {
    String name
}

json {
    message "Hello ${name}!"
}
```

`model`のブロックにコントローラから受け取るモデルのデータを定義して、`json`のブロックでレンダリングのフォーマットを指定しています。

この状態でAPIをたたいてみると以下のようになります。

```
$ curl localhost:8080/hello
{"message":"Hello yamada!"}
```

`json`ブロックの定義に従ってうまく表示されました。


## ドメインクラスのモデルをレンダリングしてみる

適当なドメインクラスと、コントローラを作成します。

ドメインクラス:

```
class Person {
    String name
    Integer age
}
```

コントローラ:

```
import grails.rest.RestfulController

class PersonController extends RestfulController {

    static responseFormats = ['json']

    PersonController() {
        super(Person)
    }
}
```

この状態で適当なデータいれてAPIをたたいてみると以下のようになります。

```
$ curl localhost:8080/person/show/1
{"class":"grails.sample.json.views.Person","id":1,"age":20,"name":"yamada"}
```

デフォルトの挙動を変更するために、grails-app/views/person/show.gsonを次のように作成します。

```
model {
    Person person
}

json {
    name person.name
    age person.age
}
```

再度APIを叩いてみると...

```
$ curl localhost:8080/person/show/1
{"name":"yamada","age":20}
```

今度は`json`ブロックで定義した`name`と`age`だけが表示されました。

## テンプレートを使ってみる

GSPと同じでテンプレートが使えます。テンプレートはファイルのプレフィックスに`_`を付与します。

例えば`_person.json`を以下のように定義して、

```
model {
    Person person
}

json {
    name person.name
    age person.age
}
```

index.gson、show.gsonでこのテンプレートを使う場合は以下のようにします。

index.gson:

```
model {
    Collection<Person> personList
}

json g.render(template: 'person', collection: personList, var:'person')
```

show.gson:

```
model {
    Person person
}

json g.render(template: 'person', model: [person: person])
```

実行すると次のようになります。

```
$ curl localhost:8080/person
[{"name":"yamada","age":20}]

$ curl  localhost:8080/person/show/1
{"name":"yamada","age":20}
```

上記は`g.render`を使っていますが、以下のようにも書けます。動作は変わりません。

index.json:

```
model {
    Collection<Person> personList
}

json tmpl.book(personList)
```

show.gson:

```
model {
    Person person
}

json tmpl.book(person)
```

## まとめ

今までJSONのレンダリングは独自のカスタムマーシャラなんちゃらというクラスを実装したりなど、汎用的にいろいろとやろうとすると面倒くさいことも多かったのですがJSON Viewsによってだいぶ簡単に書けそうな印象です。

特に個人的にはURLのリンクなどはJSONに含む場合カスタムマーシャラなんかだと簡単にはg.linkなどリンク生成機能にアクセスできない、かつフロントエンドの知識をカスタムマーシャラに登場させる気持ち悪さがあったのですが、このへん全てビューに収まると非常にしっくりきます。

今日書いた内容はほぼ公式リポジトリの https://github.com/grails/grails-views に書いてある内容です。もう少し詳しく知りたい方は参照してみてください。

ではでは。