I am struggling with getting JSON API, and rendering of json for domain classes. I am using Grails v3.3.3 and JsonViews 1.2.7
If I expose a domain class by using @Resource annotation this automatically generates a controller and 'default' json output.
However I want some control over what's happening, so I have a another domain class (Customer, and Site in my demo app, where Customer hasMany Sites).
I do not use the @Resource annotation in either of these domain classes.
I manually create two controllers called CustomerRestController and SiteRestController by hand - and use the UrlMappings to expose the URI. (one using the '(resources: controller)' form and the other with declared explicit controller and actions:
class UrlMappings {
static mappings = {
"/api/customers"(resources:"customerRest")
//or try to declare with explicit mappings
"/api/sites" (controller: "siteRest", action: "index")
"/api/sites/$id" (controller: "siteRest", action: "show", view: "show")
"/$controller/$action?/$id?(.$format)?"{
constraints {
// apply constraints here
}
}
"/"(view:"/index")
"500"(view:'/error')
"404"(view:'/notFound')
}
}
So lets look first at what happens for SiteRestController (with simple debug println to show it's being called in the console). I have used the GORM data service model and just defined an interface in services and let Grails auto build the serviceImpl and then inject this into the controller. I have declared the response format to be [json]
@CompileStatic
class SiteRestController extends RestfulController {
static responseFormats = ['json']
SiteService siteService
SiteRestController() {
super (Site)
println "siteRest default constructor controller created"
}
def index (Integer max)/*(@PathVariable String manufacturerName)*/ {
println ("site.index: invoked index action on customer restful controller ")
respond siteService.list([:]), model:[siteCount: siteService.count()]
}
def show(Long id) {
println "site.show: show on SiteRestController called with $id"
respond siteService.get(id)
}
}
I have manually created /views/site/_site.gson, index.gson and show.gson
//_site.gson
import model.Site
println "_site template called " //added to check that template is being called
model {
Site site
}
json jsonapi.render (site)
to show that view is being ignored I've edited the show.gson as follows
import model.Site
model {
Site site
}
json g.render ([name:"will"])
and the index.gson view as
import model.Site
model {
List<Site> siteList
Long siteCount
}
println "index.gson more data"
json {
name "hello william"
}
So when I fire up the app and invoke the '/api/sites' url I get this. Which is just a standard rendering and doesn't use the _site.gson - and ignores my index.gson
[
{
"id": 1,
"name": "headoffice",
"customer": {
"id": 1
}
}
]
And if I call '/api/sites/1' i get the following (this has clearly invoked the the _sites.gson template, but my 'show.gson' was modified to not use template and this is clearly being ignored)
_site template called
{
"data": {
"type": "site",
"id": "1",
"attributes": {
"name": "headoffice"
},
"relationships": {
"customer": {
"links": {
"self": "/customer/show/1"
},
"data": {
"type": "customer",
"id": "1"
}
}
}
},
"links": {
"self": "/site/show/1"
}
}
I also tried to do a deep rendering from customers view template like this
import model.Customer
model {
Customer customer
}
json jsonapi.render (customer, [deep:true, jsonApiObject:true])
which ignores my sites details on deep rendering when query /api/customers/1. Notice the site just shows the default id and doesn't seem to call the _site.gson:
{
"jsonapi": {
"version": "1.0"
},
"data": {
"type": "customer",
"id": "1",
"attributes": {
"name": "hsbc"
},
"relationships": {
"sites": {
"data": [
{
"type": "site",
"id": "1"
}
]
}
}
},
"links": {
"self": "/customer/show/1"
}
}
So I'm not understanding what's going one here. Grails has its own internal generated defaults and is ignoring the views etc that I have provided and doesn't seem to be doing the deep rendering when requested to do so.
Would anyone advise what why my views/templates are not being called as expected?