I am looking for best practices / solution to make 'respond' method generate extra metadata in the resulting json along with the collection of entities got from DB.
Basically I wanted to implement pagination using that metadata in my frontend single-page-application (SPA) built with angularJS and Restangular plugin.
PS: angularJS's $resource or Restangular expect collection results as JS array.
Standard Grails JsonCollectionRenderer/JsonRenderer
ignores the metadata supplied to 'respond' in the map argument.
I came across following article which is implementing custom JsonRenderer, but I looking for simpler/flexible solution to make 'respond' output metadata via tweaking custom JsonCollectionRenderer
in resources.groovy
http://groovyc.net/non-trivial-restful-apis-in-grails-part-2/
My RestfulController:
@Secured(value=["hasRole('ROLE_USER')"])
class DrugController extends RestfulController<Drug> {
static scaffold = true
static responseFormats = ['html', 'json', 'xml', 'hal']
static allowedMethods = [show: "GET"]
DrugController() {
super(Drug, true)
}
@Override
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
// We pass which fields to be rendered with the includes attributes,
// we exclude the class property for all responses. ***when includes are defined excludes are ignored.
//params.fetch = [recordTypeRs:"eager"] from params.fields???
respond resource.list(params),
[includes: includeFields, excludes: ['class', 'errors', 'version'],
metadata: [total: countResources(), psize: params.max, offset: params.offset?:0],
model: [("${resourceName}InstanceCount".toString()): countResources()]]
}
@Override
def show(Drug drug) {
JSON.use("deep") {
respond drug,
[includes: includeFields, excludes: ['class', 'errors', 'version']]
}
}
private getIncludeFields() {
params.fields?.tokenize(',')
}
def search(Integer max) {
params.max = Math.min(max ?: 10, 100)
def c = Drug.createCriteria()
def results = c.list(params) {
//Your criteria here with params.q
and {
like('ndc', params.ndc?params.ndc+'%':'%')
like('recordTypeJ.j017', params.labelerName?'%'+params.labelerName+'%':'%')
like('recordTypeE.e017', params.productName?'%'+params.productName+'%':'%')
}
//cache(true)
}
log.debug(results.totalCount)
respond results, model:[drugCount: results.totalCount]
}
}
I have following in my resources.groovy.
// register Renderers/CollectionRenderers for all domain classes in the application.
for (domainClass in grailsApplication.domainClasses) {
"json${domainClass.shortName}CollectionRenderer"(JsonCollectionRenderer, domainClass.clazz)
"json${domainClass.shortName}Renderer"(JsonRenderer, domainClass.clazz)
"hal${domainClass.shortName}CollectionRenderer"(HalJsonCollectionRenderer, domainClass.clazz)
"hal${domainClass.shortName}Renderer"(HalJsonRenderer, domainClass.clazz)
}