I am working on a project using grailsViews and jsonApi format. I am using Grails v3.3.9 and jsonViews v1.2.10.
So the views provides template support for generating jsonApi from your domain model, but I can't find the inverse that allows you to build a domain object (and tree) from data that's posted/patched.
I managed to get this clumsy version to work but it's a quick hack.
In essence I had to override the createResource mthod in RestfulController. What this does is grab the post body and parses it. It dips into the json and finds the attributes and tries to use the bindData for this simple attributes map.
Relationships are harder. I have to iterate over these and see if there's any children with data for each tag.
I then have to addTo<Tag>
(for each entry if I can find an instance in the domain model to add to the collection. There are lots of problems with this code - but it does actually get around to persisting a new OrgRoleInstance.
//works - needs lots of improvement !! overwites, lookups etc
@Override
protected <T extends OrgRoleInstance> T createResource() {
def instance = super.resource.newInstance()
RequestFacade requestFacade = getObjectToBind()
BufferedReader bodyReader = requestFacade.request.getReader()
long bodyLength = requestFacade.request.getContentLengthLong()
String jsonBody = bodyReader.text
//String strippedBackJson = jsonBody.replaceAll("\\s+","")
JsonSlurper slurper = new JsonSlurper()
def body = slurper.parseText (jsonBody)
def data = body.data
String bodyDataType = body.data.type
//json views api seems to show the class starting in lower case - change to uppercase
String dataType = convertFirstCharToUppercase (bodyDataType)
Map attributes = body.data.attributes
Map relationships = body.data.relationships
//wrap in a try block
//def jsonClassRef = Class.forName(toToBindString) - https://stackoverflow.com/questions/13215403/finding-a-class-reflectively-by-its-simple-name-alone
//assume users know what they are doing ! - just sanity check simple name
String resClassSimpleName = resource.getSimpleName()
assert dataType == resClassSimpleName
//needs a custom bindData
bindData instance, attributes //getObjectToBind()
//process any relationships and bind these
relationships.each {tag, value ->
def dataArray = value.data
for (item in dataArray) {
def jsonType = item['type']
//convert first char to uppercase
String type = convertFirstCharToUppercase (jsonType)
def id = Long.parseLong (item['id'])
//with type and id try and find in existing domain model
def refEntity
Class<?> domainClass = domainClassLookupByName (type)
if (domainClass) {
refEntity = domainClass.get (id)
}
//help cant overwrite foreign key - clone the mag?
if (refEntity) {
def prop = convertFirstCharToUppercase(tag)
instance."addTo$prop" (refEntity)
//if (refEntity.validate())
//refEntity.save (failOnError:true)
}
instance
}
}
//bindData instance, relationships //getObjectToBind()
instance
}
The post data looks like this (i pretty printed the output from the get action on another record end edited that.
Note think it's a defect - but the jsonapi rendering for type: does lowercase char for a type rather than capital case as you'd expect - I've had to compensate for that).
I was hoping that the grails team might have been doing something on this. If not I'll request a feature enhancement.