JSON RESTful API for GORM
Last updated by padcom 4 months ago DOWNLOAD
Please note that all development (including the examples) have recently been migrated to GitHub. Please update your branches!
See GitHubfor known issues.Sources: https://github.com/padcom/grails-json-rest-api
Continuous 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 instanceThe "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 static
exposeproperty, for example:packagedomainclass Person { static expose = 'person'
String firstName String lastName }
becomes /context/api/person
packagedomainclass PersonAddress { static expose = 'person-address'
Long personid String address }
becomes /context/api/person-address
Any parameter that works with the
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
For example if an Author hasMany = [ books: Book ] then the following will be the outcome of GET on /api/author/1:
{ data: { books: [1, 2, 3], name: "Author name" }, success: true, message: "", count: 1 }Quering /api/book/1 will yield the following result:
{ data: { author: 1, title: "Some title" }, success: true, message: "", count: 1 }If you want you can change the book-to-author assignment by sending PUT with the following payload at /api/book/1:
{ data: { author: 2 } }If the Author with id=2 does not exists it will not be retrieved from the database thus anullvalue 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'With this line in place instead of /context/api the services will be available under /context/json.
Custom retrieval functions and field exclusion
To customize how instances are retrieved (instead of using the
DomainClass.list()method) there's a special static property calledapithat 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
The
paramsparameter is the exact same one passed on to controller. Here's an example that shows a customized api:packagedomainclass 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}" } }
This is a pretty useless example but it shows the way to implement custom retrieval functions.
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-examplesTo use those examples you need to have them cloned on the same level in the same folder as the actual plugin so that the directory structure looks like this:
grails-json-rest-api grails-json-rest-api-examplesMotivation
The main motivation behind this plugin was to make it extremely easy to use GORM and Grails with Ext JS and the
JsonStoreit provides. So for example, to utilize theJsonStorefor aPersondomain 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' } ] });To provide writing capabilities the following store definition is sufficient for all CRUD operations:
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 }) });To provide remote pagination and sorting capabilities define your store with an additional
paramNamesproperty 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 }) });This ensures that the parameters required by
DomainClass.list()method match whatJsonStoreis 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
posted on 2011-12-30 14:49 restService 阅读(878) 评论(0) 收藏 举报
浙公网安备 33010602011771号