Сериализация тела запроса POST в массив с помощью FOSRestBundle

Я пытаюсь создать веб-службу Rest, используя Symfony 3 и FOSRestBundle.
Я пришел из Spring + Jackson, поэтому я пытаюсь сделать так, чтобы вы могли передавать объекты контроллерам в качестве тела запроса, которые становятся параметрами функции и возвращать объекты, которые сериализуются в json, пока мне удалось заставить его работать для всего, кроме массивов.
Это мой код:

конфигурация:

#FOSRestBundle
fos_rest:
    param_fetcher_listener: true
    body_listener: 
        enabled: true
        decoders:
            json: fos_rest.decoder.json
    format_listener:
        rules:
            - { path: ^/, priorities: [ json ], fallback_format: json, prefer_extension: true }

    body_converter:
        enabled: true
        #validate: true

    view:
        mime_types:
            json: ['application/json', 'application/json;version=1.0', 'application/json;version=1.1']
        view_response_listener: 'force'
        formats:
            xml:  false
            json: true
        templating_formats:
            html: true

    exception:
        codes:
            'Symfony\Component\Routing\Exception\ResourceNotFoundException': 404
            'Doctrine\ORM\OptimisticLockException': HTTP_CONFLICT
        messages:
            'Symfony\Component\Routing\Exception\ResourceNotFoundException': true
    allowed_methods_listener: true
    access_denied_listener:
        json: true

это контроллер

<?php

namespace AppBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use JMS\DiExtraBundle\Annotation\Inject;
use FOS\RestBundle\Controller\Annotations\Post;
use FOS\RestBundle\Controller\Annotations\View;
use FOS\RestBundle\Controller\FOSRestController;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;

class DefaultController extends FOSRestController {

    /**
     * @Post("/rest", name="rest_test")
     * @ParamConverter("myArr", converter="fos_rest.request_body")
     * @View
     * @param Request $request
     */
    public function restAction(Request $request, array $myArr) {
        return $myArr;
    }
}

Когда я пытаюсь вызвать это из своего оставшегося клиента (указав [1, 2] в качестве тела запроса), я получаю эту ошибку:

{
  "code": 500,
  "message": "Converter 'fos_rest.request_body' does not support conversion of parameter 'myArr'."
}

Если я превращу myArr в объект (то есть я изменю его тип с array на MyObject, содержащий переменную number myVar) и отправлю данные, которые отражают структуру этого объекта (например, {"myVar": 2} ), он работает нормально, но не работает с множество.


person valepu    schedule 29.09.2016    source источник


Ответы (2)


После нескольких дней игры с кодом и этой приятной беседы с одним из сотрудников FoS https://github.com/FriendsOfSymfony/FOSRestBundle/issues/1582 я обнаружил, что если вы используете JMS Serializer Bundle (который, я думаю, есть у всех), вы можете просто написать array в поле класса преобразователя параметров, и он десериализует его в массив. Я должен был попробовать это раньше, я думаю

@ParamConverter("myarr", class="array", converter="fos_rest.request_body")

Он может даже десериализовать массивы объектов (я думаю, если они одного класса)

@ParamConverter("myarr", class="array<Namespace/Class>", converter="fos_rest.request_body")

ОБНОВЛЕНИЕ. Я обновляю этот вопрос, так как перестал использовать JMS Serializer и начал использовать Symfony Serializer, который имеет другой синтаксис для массивов объектов:

@ParamConverter("myarr", class="Namespace/Class[]", converter="fos_rest.request_body")

Синтаксис обычных массивов остался нетронутым.

person valepu    schedule 08.10.2016
comment
Привет, не могли бы вы мне помочь, я пытаюсь настроить fos_rest для использования сериализатора symfony, но не нашел решения, как вы его настроили? - person Andrew Vakhniuk; 10.06.2021
comment
@AndrewVakhniuk Все конфигурации, которые я использую, опубликованы в моем вопросе, но это для Symfony 3, и я некоторое время не работал над этим, поэтому сейчас все может быть по-другому. Вы проверили их github? - person valepu; 10.06.2021

Преобразователь тела FOS Rest предназначен для заполнения объектов, а не массивов. Вы можете попробовать реализовать свой собственный преобразователь параметров (см. эту документацию), но я действительно не уверен, что вы сможете добиться того, чего хотите.

В любом случае, работа с объектами не будет чище? Это позволит вам быть уверенным, что данные, которые вы получаете, соответствуют вашим ожиданиям, использовать проверки и так далее...

person Boulzy    schedule 30.09.2016
comment
Я всегда могу создать объект с массивом внутри, я думаю (еще не пробовал). Но бывают ситуации, когда мне нужно отправить, например, массив идентификаторов, чтобы указать бэкенду выполнять операции с набором элементов. - person valepu; 30.09.2016
comment
Может быть, тогда ваш дизайн REST неверен? REST на самом деле не предназначен для выполнения операций с несколькими ресурсами с одним запросом. Если вам действительно нужно это сделать, я думаю, вам придется сделать это вручную, потому что FOS REST не предназначен для этого. :/ - person Boulzy; 30.09.2016
comment
В документации fosrestbundle даже говорится, что вы можете использовать автоматически сгенерированный метод PATCH (еще не пробовал) для частичного обновления подмножества ресурсов symfony.com/doc/current/bundles/FOSRestBundle/ , но это был просто пример... я хорошенькая уверен, что во многих случаях вам может понадобиться отправить массив в вызове REST. Кроме того, Spring + Jackson позволяет отправлять массив (любого типа) в качестве тела запроса. - person valepu; 30.09.2016
comment
Действительно есть, я просто говорю, что это не самый общий вариант использования и что его нужно обрабатывать вручную. Это становится вопросом мнения, я не думаю, что для этого действительно существует стандарт, но ИМО, идентификаторы ресурсов должны храниться в URI. Или как фильтр в параметре запроса, если это необходимо, но тело оставить для самих ресурсов. Если вы сделаете это с параметром запроса, аннотация FOS Rest QueryParam позволит вам получить массив идентификаторов, но для управления этим все еще есть хотя бы одна строка кода. - person Boulzy; 30.09.2016