JSON RESTful API for GORM
Dependency :
compile "org.grails.plugins.json-rest-api:json-rest-api:1.0.11"
Summary
Installation
grails install-plugin json-rest-apiDescription
Please note that all development (including the examples) have recently been migrated to GitHub. Please update your branches!
See GitHub for known issues.Sources: https://github.com/padcom/grails-json-rest-apiContinuous integration: http://dev.aplaline.com/hudson/job/grails-json-rest-api/
Installation
grails install-plugin json-rest-apiUsage
After installing this plugin a subset of RESTful API is available under/<i>context/api/domain-class-name . This means:
- GET on
/context/api/domain-class-namereturns a list of domain objects (possible arguments are the same as for theDomainClass.list()method argument map) - POST on
/context/api/domain-class-namecreates a new instance - GET on
/context/api/domain-class-name/idretrieves the given instance - PUT on
/context/api/domain-class-name/idupdates the given instance by ID - DELETE on
/context/api/domain-class-name/iddeletes the given instance
The "context" part of the paths above is the application context (note the leading forward slash). In your case it's going to be different!
For example if your application is called "my-app" it's going to be /my-app/api/domain-class-name/ Mappings
Domain class names are mapped using a staticexpose property, for example:package domainclass Person { static expose = 'person' String firstName String lastName }
package domainclass PersonAddress { static expose = 'person-address' Long personid String address }
DomainClass.list(params) method works out of the box so paging and probably server-side sorting work.Domain classes and relations
Since version 1.0.6 this plugin supports list and single instances of relations. There is however one known limitations to that.- domain classes have to have numeric id
{ data: { books: [1, 2, 3], name: "Author name" }, success: true, message: "", count: 1 }{ data: { author: 1, title: "Some title" }, success: true, message: "", count: 1 }{ data: { author: 2 } }
If the Author with id=2 does not exists it will not be retrieved from the database thus a null value will be assigned to the field. If the author cannot be null then an error will be returned just like you'd assign a null directly to the field.
This has been a long awaited feature. If you find it useful or if it breaks please drop me a note (padcom@gmail.com)Changing the root for the API
Changing the root for the API is possible using the following configuration option in Config.groovy:grails.'json-rest-api'.root = '/json'Custom retrieval functions and field exclusion
To customize how instances are retrieved (instead of using theDomainClass.list() method) there's a special static property called api that by convention should contain 2 closures:
- excludedFields = list to mark certain fields as being excluded from the rendered response
- list(params) to retrieve the actual instances
- count(params) to retrieve total count of instances
params parameter is the exact same one passed on to controller. Here's an example that shows a customized api:package domainclass Person { static expose = 'person' static api = [ excludedFields: [ "fullName" ] list : { params -> Person.list(params) }, count: { params -> Person.count() } ] String firstName String lastName String getFullName() { "${firstName} ${lastName}" } }
Please bear in mind that both functions need to operate on the same set of data so if the full list retrieved by thelistclosure contains 100 elements this is the exact number to be retrieved by thecountclosure. It's best achieved by using the same criteria for both closures.
Examples
https://github.com/padcom/grails-json-rest-api-examplesgrails-json-rest-api grails-json-rest-api-examples
Motivation
The main motivation behind this plugin was to make it extremely easy to use GORM and Grails with Ext JS and theJsonStore it provides. So for example, to utilize the JsonStore for a Person domain class you'd normaly define a read-only store like this:var personStore = new Ext.data.JsonStore({ url: '/example/api/person', restful: true, root: 'data', totalProperty: 'count', messageProperty: 'message', fields: [ { name: 'id', type: 'int' }, { name: 'firstName' }, { name: 'lastName' } ] });
var store = new Ext.data.JsonStore({ url: '/example/api/person', restful: true, root: 'data', totalProperty: 'count', messageProperty: 'message', fields: [ { name: 'id', type: 'int' }, { name: 'firstName', allowBlank: false }, { name: 'lastName', allowBlank: false } ], writer: new Ext.data.JsonWriter({ encode: false }) });
paramNames property like this:var store = new Ext.data.JsonStore({ url: '/example/api/person', restful: true, root: 'data', totalProperty: 'count', messageProperty: 'message', paramNames: { start: 'offset', limit: 'max', sort: 'sort', dir: 'order' }, fields: [ { name: 'id', type: 'int' }, { name: 'firstName', allowBlank: false }, { name: 'lastName', allowBlank: false } ], writer: new Ext.data.JsonWriter({ encode: false }) });
DomainClass.list() method match what JsonStore is sending.Changes
1.0.8
- added option to exclude properties from rendered JSON
1.0.7
- fixed problem with response being 200 instead of 500 when it was not possible to create an instance
1.0.6
- added one-level traversing of relations when rendering JSON