json - Render metadata for pagination from Grails RestfulController index/search actions -
i looking best practices / solution make 'respond' method generate metadata in resulting json along collection of entities got db.
basically wanted implement pagination using metadata in frontend single-page-application (spa) built angularjs , restangular plugin.
ps: angularjs's $resource or restangular expect collection results js array.
standard grails jsoncollectionrenderer/jsonrenderer
ignores metadata supplied 'respond' in map argument.
i came across following article implementing custom jsonrenderer, looking simpler/flexible solution 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) // pass fields rendered includes attributes, // exclude class property responses. ***when includes defined excludes ignored. //params.fetch = [recordtypers:"eager"] 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 params.q , { 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 resources.groovy.
// register renderers/collectionrenderers domain classes in application. (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) }
based on ideas from
http://mrhaki.blogspot.com/2013/12/grails-goodness-rendering-partial.html
http://groovyc.net/non-trivial-restful-apis-in-grails-part-2/
- creat custom collectionrenderer e.g., sumojsoncollectionrenderer.groovy
import grails.converters.json import grails.rest.render.rendercontext import grails.rest.render.json.jsoncollectionrenderer import org.codehaus.groovy.grails.web.mime.mimetype import groovy.transform.compilestatic import static groovy.transform.typecheckingmode.skip @compilestatic class sumojsoncollectionrenderer extends jsoncollectionrenderer{ sumojsoncollectionrenderer(class componenttype) { super(componenttype) } public sumojsoncollectionrenderer(class componenttype, mimetype... mimetypes) { super(componenttype, mimetypes) } @compilestatic(skip) @override protected void renderjson(object, rendercontext context) { log.debug(object) log.debug(object.size()) log.debug(object.gettotalcount()) map tobject = ['results':object] if(context.arguments?.metadata) { tobject['metadata'] = context.arguments.metadata } super.renderjson(tobject,context) } }
register custom collectionrenderer @ resource.groovy
for (domainclass in grailsapplication.domainclasses) { "json${domainclass.shortname}collectionrenderer"(sumojsoncollectionrenderer, domainclass.clazz) "json${domainclass.shortname}renderer"(jsonrenderer, domainclass.clazz) "hal${domainclass.shortname}collectionrenderer"(haljsoncollectionrenderer, domainclass.clazz) "hal${domainclass.shortname}renderer"(haljsonrenderer, domainclass.clazz) }
request/response
http://api.mydomain.com:8080/apiapp/drugs.json?max=5&fields=ndc,id
{"results":[{"id":1,"ndc":"000020803031"},{"id":2,"ndc":"000021200011"},{"id":3,"ndc":"000021407011"},{"id":4,"ndc":"000021975901"},{"id":5,"ndc":"000023004751"}],"metadata":{"total":851,"psize":5,"offset":0}}
Comments
Post a Comment