GrailsView анализирует пост-данные jsonApi — занимается ли команда Grails универсальным решением в jsonViews?

Я работаю над проектом, используя формат 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 что-то делала для этого. Если нет, я попрошу улучшение функции.


person WILLIAM WOODMAN    schedule 24.01.2019    source источник


Ответы (1)


Ну, есть объекты-команды, и с технической точки зрения вы можете использовать объекты домена в качестве объектов-команд. Однако я не рекомендую использовать объекты домена в качестве командных объектов вне игрушечного приложения из-за неотъемлемых рисков безопасности, поэтому я думаю, что это вроде как нет...

Однако я бы посоветовал вам использовать объекты команд, потому что они дают вам базовую проверку и в некотором роде документируют API ваших контроллеров. Одно замечание: я обычно стараюсь поддерживать свет командных объектов, не добавляя службы или не выполняя вызовы, по тем же причинам, по которым вы не делаете это в доменах, потребление памяти и вызовы БД относятся к службам в переходах. Кроме того, я обычно передаю параметры из командного объекта в «красиво» выложенный API, если только командные объекты не представляют документ Джона, где это было бы ovekill.

Существует также подключаемый модуль команд, который предоставляет объекты команд, более согласованные с конфигурацией, как и другие артефакты Grails. Я написал это, так что вы можете принять это с солью :)

person virtualdogbert    schedule 25.01.2019
comment
Хорошо, я получаю командный объект, но проблема остается той же концептуально - модель jsonviews/rest, как описано, работает с классами предметной области, поскольку рендеринг должен понимать отношения в модели. Однако реализованные представления json могут генерировать выходные данные в формате jsonApi (в ответ на запрос GET). Однако я не могу найти поддержки для обработки содержимого тела jsonApi как POST в домен или объекты команды. - person WILLIAM WOODMAN; 25.01.2019
comment
Я думаю, что тогда я что-то упустил в вашем вопросе, что вы подразумеваете под содержимым тела jsonApi? Можете ли вы привести пример? Если вы просто имеете в виду данные json, поступающие в тело сообщения, они автоматически будут привязаны к объекту команды в подписи контроллера: docs.grails.org/latest/guide/theWebLayer.html#commandObjects - person virtualdogbert; 26.01.2019