Rendering JSON for Ember.js with Grails and JSON Views

While learning Ember.js, one of my goals has been to use as much of it out-of-the-box (OOTB) as possible. With any framework, the moment I find myself customizing too many things I feel like I'm defeating the purpose of using said framework. One of Ember's OOTB features is ember-data's DS.RESTSerializer and DS.RESTAdapter. For this post I'm going to be speaking more towards the DS.RESTSerializer.

DS.RESTSerializer expects a specific structure for the JSON for both collections and objects.

Student Collection

{
  students: [
   {
     id: 1,
     firstName: "Myles",
     lastName: "Kennedy"
   },
   {
     id: 2,
     firstName: "Mark",
     lastName: "Tremonti"
   }
]}

Note that the collection is named with students.

Student Object

{
  student: {
    id: 1,
    firstName: "Myles",
    lastName: "Kennedy"
  }
}

Here, the object is named with the student variable. The problem we run into with Grails is the default renderer doesn't include named collections or objects. For example, a collection of students would like like this:

[
   {
     id: 1,
     firstName: "Myles",
     lastName: "Kennedy"
   },
   {
     id: 2,
     firstName: "Mark",
     lastName: "Tremonti"
   }
]

It used to be the case that Grails promoted the use of custom marshallers. Since Grails 3.1, the preferred way is now using JSON Views. In fact, the Grails documentation says:

Since Grails 3.1, JSON views are considered by the Grails team the best way to present JSON output for the client, and for that reason the section on writing custom marshallers has been removed from the user guide.

JSON Views can also be found in Spring Boot and since Grails 3 is built on Spring Boot, we can use them in Grails as well, and in a very groovy way.

For the above examples, we'll first need to create our JSON View template. Assuming we have a controller called StudentController and a URLMapping of "/students"(resources: "student"), in the grails-app/views/student folder, create a file called _student.gson with the following code:

import your.package.Student

model {  
    Student student
}

json g.render(student)  

Nothing too exciting here. Next, create grails-app/views/student/index.gson. This is what will help render our JSON for a collection of students.

import your.package.Student

model {  
  Iterable<Student> studentList
}

json {  
  students g.render(template: 'student', collection: studentList ?: [], var: 'student')
}

I've told it to render using the _student template, told it what to use for the collection and gave it the variable name to use. The key here though is what happens before the g.render call; students. Now, when we call our RESTful endpoint to get a list of students using something like http://localhost:8080/students, we'll get the appropriate structure for Ember.

For the http://localhost:8080/students/1 endpoint, we'll create grails-app/views/student/show.gson with the following contents:

import your.package.Student

model {  
  Student student
}

json {  
  student g.render(template: "student", model: [student: student])
}

Very similar here. We pass in the model to a named template. And we call that object student. And that's really it. This is 10 x's simpler than what it was like to do this using custom marhsallers and in fact, I never got it fully working.

As a side note, I also added an interceptor for putting in the CORS header data so that my ember app could talk to my grails app over different ports.

class CorsInterceptor {

  CorsInterceptor() {
    matchAll()
  }

  boolean before() {
    header( "Access-Control-Allow-Origin", "http://localhost:4200" )
    header( "Access-Control-Allow-Credentials", "true" )
    header( "Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE" )
    header( "Access-Control-Max-Age", "3600" )
    true
  }

  boolean after() { true }
}