Serialize POST request body into array with FOSRestBundle

valepu picture valepu · Sep 29, 2016 · Viewed 8.7k times · Source

I am trying to make a Rest web service using Symfony 3 and FOSRestBundle.
I come from a Spring + Jackson background so i'm trying to make it so that you can pass objects to controllers as request body that become function parameters and return objects that get serialized into json, so far i managed to make it work for everything except for arrays.
This is my code:

configuration:

#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

This is the controller

<?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;
    }
}

When i try to call this from my rest client (putting [1, 2] as request body) i receive this error:

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

If i turn myArr into an object (that is i change its type from array to MyObject, containing the number variable myVar) and send data that reflects that object structure (such as {"myVar": 2} ) it works fine, but it doesn't work with an array.

Answer

valepu picture valepu · Oct 8, 2016

After days of toying with the code and this nice conversation with one of the collaborators of FoS https://github.com/FriendsOfSymfony/FOSRestBundle/issues/1582 i have discovered that, if you are using the JMS Serializer Bundle (Which I think everyone has), you can just write array in the class field of the param converter and it will deserialize it into an array. I should've tried it earlier i guess

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

It can even deserialize arrays of objects (as long as they are the same class, i guess)

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

UPDATE I'm updating this question since i stopped using JMS Serializer and started using the Symfony Serializer, which has a different syntax for arrays of objects:

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

Normal arrays syntax is untouched