Я работаю над проектом, используя формат grailsViews и jsonApi. Я использую Grails v3.3.9 и jsonViews v1.2.10.
Таким образом, представления обеспечивают поддержку шаблонов для создания jsonApi из вашей модели домена, но я не могу найти обратное, которое позволяет вам создавать объект домена (и дерево) из данных, которые опубликованы/исправлены.
Мне удалось заставить эту неуклюжую версию работать, но это быстрый взлом.
По сути, мне пришлось переопределить метод createResource в RestfulController. Это захватывает тело сообщения и анализирует его. Он погружается в json, находит атрибуты и пытается использовать bindData для этой простой карты атрибутов.
Отношения сложнее. Я должен перебрать их и посмотреть, есть ли дочерние элементы с данными для каждого тега.
Затем мне нужно addTo<Tag>
(для каждой записи, если я могу найти экземпляр в модели домена для добавления в коллекцию. С этим кодом много проблем, но на самом деле он позволяет сохранить новый 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
}
Пост-данные выглядят следующим образом (я довольно распечатал вывод действия get на другом конце записи, отредактировав его.
Обратите внимание, что это дефект, но рендеринг jsonapi для типа: делает нижний регистр char для типа, а не заглавный регистр, как вы ожидаете - мне пришлось это компенсировать).
Я надеялся, что команда Grails что-то делала для этого. Если нет, я попрошу улучшение функции.