RestResponder のビュー選択ロジック

  • Controller クラスで respond メソッドを打った時の挙動についてわかったことをダラダラ書いておく

前提

  • Grails で rest profile でアプリを作成しているとき
  • Grails は 3.2.4 のときの挙動

RestResponder って…?

  • rest profile で起動すると、Controller クラスに勝手に implements されるクラス(trait)

respond メソッドが打たれた時の大まかな流れ

ソース

流れ

  1. RestResponder#render()
    • 単なる delegate メソッド
  2. RestResponder#internalRespond()
    1. リクエストの MIME タイプから適切なレスポンス MIME タイプを入れる
    2. RendererRegistry から MIME タイプ、respond メソッドに指定されたオブジェクトクラス、オブジェクトから適切な Renderer を引っ張ってくる
      • RendererRegistry は特に指定してなければ、 org.grails.plugins.web.rest.render.DefaultRendererRegistry クラスのインスタンスが作られる
      • Renderer も特に設定しなければ grails.plugin.json.renderer.JsonViewJsonRenderer クラスのインスタンスが返ってくる
        • 実装はほとんど grails.views.mvc.renderer.DefaultViewRenderer
      • 実は org.springframework.validation.Errors クラスのインスタンスが引数に指定されたときは処理ロジックが違ったり…
  3. DefaultViewRenderer#render()
    • こいつが本命
    • Controller クラスで指定されたオプションの解釈、テンプレートの解決、描画まですべて受け持っている

テンプレートの解決方法

  1. ビュー名 の解決
    1. respond メソッド呼び出し時に渡した view オプション
    2. なければ、アクション名
  2. ビュー URI の解決
    1. ビュー名が / から始まっている場合はそのまま使う
    2. それ以外の場合は /${コントローラ名}/${ビュー名} を設定する
  3. namespace が指定されている場合はさらに頭に /${namespace} を追加する
  4. ここまでで一度テンプレートファイルがあるかどうか探してみる
  5. 見つからなければ、 respond メソッド呼び出し時に渡したオブジェクトのクラスから適切なテンプレートを探す
    • ここでも見つからなければ object/_object.gson に落ちる

RestResponder にまつわるTips

respond に渡したインスタンスに対応するテンプレートで描画されない!

  • respond に渡しているインスタンスは、あるモデルクラスの関連クラスのインスタンスを渡していませんか?
    • 渡している場合は、そのインスタンスのクラス名を要チェキ
    • 以下のようになっている場合は、そのまま渡してもテンプレート解決できない
class jp.co.hoge.domain.user.Worker_$$_jvst806_3 なんかくっついてる ^^^^^^^^^^^^^
  • 以下のようにビュー名を直接指定して、テンプレートを見つけさせる
respond([mission: mission], view: '/mission/_mission')
- 渡すモデル、ビュー名は全部しっかり指定する - インスタンスのクラス名に余分なものがついているので、Grails によるモデルの補完、ビュー名の解決はうまく動かない