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/

  1. 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

Popular posts from this blog

php - render data via PDO::FETCH_FUNC vs loop -

c++ - OpenCV Error: Assertion failed <scn == 3 ::scn == 4> in unknown function, -

The canvas has been tainted by cross-origin data in chrome only -