how to return json encoded form errors in symfony

symfony form validation error message
symfony ajax form errors
symfony validate json request
symfony 4 form get errors
symfony form json
symfony why is form not valid
symfony form submit
symfony 4 form validator

I want to create a webservice to which I submit a form, and in case of errors, returns a JSON encoded list that tells me which field is wrong.

currently I only get a list of error messages but not an html id or a name of the fields with errors

here's my current code

public function saveAction(Request $request)
{
    $em = $this->getDoctrine()->getManager();

    $form = $this->createForm(new TaskType(), new Task());

    $form->handleRequest($request);

    $task = $form->getData();

    if ($form->isValid()) {

        $em->persist($task);
        $em->flush();

        $array = array( 'status' => 201, 'msg' => 'Task Created'); 

    } else {

        $errors = $form->getErrors(true, true);

        $errorCollection = array();
        foreach($errors as $error){
               $errorCollection[] = $error->getMessage();
        }

        $array = array( 'status' => 400, 'errorMsg' => 'Bad Request', 'errorReport' => $errorCollection); // data to return via JSON
    }

    $response = new Response( json_encode( $array ) );
    $response->headers->set( 'Content-Type', 'application/json' );

    return $response;
}

this will give me a response like

{
"status":400,
"errorMsg":"Bad Request",
"errorReport":{
        "Task cannot be blank",
        "Task date needs to be within the month"
    }
}

but what I really want is something like

{
"status":400,
"errorMsg":"Bad Request",
"errorReport":{
        "taskfield" : "Task cannot be blank",
        "taskdatefield" : "Task date needs to be within the month"
    }
}

How can I achieve that?

I am using this, it works quiet well:

/**
 * List all errors of a given bound form.
 *
 * @param Form $form
 *
 * @return array
 */
protected function getFormErrors(Form $form)
{
    $errors = array();

    // Global
    foreach ($form->getErrors() as $error) {
        $errors[$form->getName()][] = $error->getMessage();
    }

    // Fields
    foreach ($form as $child /** @var Form $child */) {
        if (!$child->isValid()) {
            foreach ($child->getErrors() as $error) {
                $errors[$child->getName()][] = $error->getMessage();
            }
        }
    }

    return $errors;
}

Sending back Validation Errors > Symfony RESTful API: Errors , Head back to newAction() and use this: $errors = $this->getErrorsFromForm() and pass it the $form object. Now, create a $data array that will eventually be our JSON response. Remember, we want type , title and errors keys. Add a type key: this is the machine name of what went wrong. To return a JSON response from an action in the legacy Symfony 1.4, you will need to change the content type of the response as first, otherwise you will end up returning a string without a specific header with the format that you're sending. The correct content type of JSON is application/json.

I've finally found the solution to this problem here, it only needed a small fix to comply to latest symfony changes and it worked like a charm:

The fix consists in replacing line 33

if (count($child->getIterator()) > 0) {

with

if (count($child->getIterator()) > 0 && ($child instanceof \Symfony\Component\Form\Form)) {

because, with the introduction in symfony of Form\Button, a type mismatch will occur in serialize function which is expecting always an instance of Form\Form.

You can register it as a service:

services:
form_serializer:
    class:        Wooshii\SiteBundle\FormErrorsSerializer

and then use it as the author suggest:

$errors = $this->get('form_serializer')->serializeFormErrors($form, true, true);

How to handle JSON requests using forms on Symfony 4 and getting , The cleanest way to deal with JSON form request Fill the entity with data; Validate entity; Throw errors if there are some return o; }; })(jQuery);. Finally you can now bind form submit and send the JSON data to our endpoint: JSON. With a version of symfony > 2.5 you can use the following code to return a json response in your controller, you only need to include the JsonResponse class and return it as a normal response. If you're using a lower version of symfony, you can use the following code instead : Have fun !

This does the trick for me

 $errors = [];
 foreach ($form->getErrors(true, true) as $formError) {
    $errors[] = $formError->getMessage();
 }

No form errors shown in JsonResponse - Symfony - json - html, The validation works fine, however I can't return JsonResponse with form error to get json data from controller you can echo json encoded data and exit. As of Symfony 2.5, you can use $form->getErrors (true) to get an array of all the errors in your form.

PHP has associative arrays, meanwhile JS has 2 different data structures : object and arrays.

The JSON you want to obtain is not legal and should be :

{
"status":400,
"errorMsg":"Bad Request",
"errorReport": {
        "taskfield" : "Task cannot be blank",
        "taskdatefield" : "Task date needs to be within the month"
    }
}

So you may want to do something like this to build your collection :

$errorCollection = array();
foreach($errors as $error){
     $errorCollection[$error->getId()] = $error->getMessage();
}

(assuming the getId() method exist on $error objects)

Nicer error messages [Raw Symfony 4], Getting Errors From Symfony Form. It would be super nice if this "just worked": if (​false Posted: Mar 24, 2018 Q A Bug report? no Feature request? yes BC Break report? no RFC? yes Symfony version 4.0 Several times now I saw new inexperienced symfony users getting confused by the Form::getErrors() method.

By reading other people's answers I ended up improving it to my needs. I use it in Symfony 3.4.

To be used in a controller like this:

$formErrors = FormUtils::getErrorMessages($form);

return new JsonResponse([
    'formErrors' => $formErrors,
]);

With this code in a separate Utils class

<?php

namespace MyBundle\Utils;

use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormInterface;

class FormUtils
{
    /**
     * @param FormInterface $form
     * @return array
     */
    public static function getErrorMessages(FormInterface $form)
    {
        $formName = $form->getName();
        $errors = [];

        /** @var FormError $formError */
        foreach ($form->getErrors(true, true) as $formError) {
            $name = '';
            $thisField = $formError->getOrigin()->getName();
            $origin = $formError->getOrigin();
            while ($origin = $origin->getParent()) {
                if ($formName !== $origin->getName()) {
                    $name = $origin->getName() . '_' . $name;
                }
            }
            $fieldName = $formName . '_' . $name . $thisField;
            /**
             * One field can have multiple errors
             */
            if (!in_array($fieldName, $errors)) {
                $errors[$fieldName] = [];
            }
            $errors[$fieldName][] = $formError->getMessage();
        }

        return $errors;
    }
}

Creating a JSON Response, and the response is generated by some functions ( echo , header() , setcookie() , …) data from Accept , Accept-Language , Accept-Charset or Accept-Encoding  How to Build a JSON Authentication Endpoint¶ In this entry, you'll build a JSON endpoint to log in your users. When the user logs in, you can load your users from anywhere - like the database. See 2b) The "User Provider" for details. First, enable the JSON login under your firewall:

New in Symfony 4.3: JSON validation (Symfony Blog), src/Entity/Book.php namespace App\Entity; use Symfony\Component\Validator\​Constraints as Assert; class Book { /** * @Assert\Json(message  A Form object is a collection of other Form objects - one for each field. And sometimes, fields have sub-fields, which are yet another level of Form objects. It's a tree. And when validation runs, it attaches the errors to the Form object of the right field.

Accepting a JSON Request Body - Documentation - Silex , A common need when building a restful API is the ability to accept a JSON encoded entity from the request body. An example for such an API could be a blog post  To return JSON from a controller, use the json() helper method on the base controller. This returns a special JsonResponse object that encodes the data automatically: 1 2 3 4 5 6 7 8 9

Validation (Symfony Docs), Validation: Validation is a very common task in web applications. if (count($​errors) > 0) { return $this->render('author/validation.html.twig', [ 'errors' => $errors, ]);  Out of the box, Symfony doesn't play super nicely with JSON. The FOSRESTBundle library is often used as it makes working with JSON data inside a Symfony application feel much more natural. Likewise, the API Platform puts JSON (primarily JSON-LD) front and central. We're going to cover both of the implementations shortly.

Comments
  • Unfortunately this didn't work for me, at least not the way I wanted. Thanks you very much for answering
  • it doesn't traverse properly the form structure if it's not a simple one and it's not returning the input fields ids/names. Maybe My explanation of the problem wasn't clear enough. Try the solution I've found, you'll understand.
  • Yes indeed, it's for one level forms only.
  • Perfect solution :)
  • for id or name of the field I mean something that I can use to target the field in form... like an html id or name of the field.
  • If your iterate with foreach($errors as $key => $error), isn't $key what you're looking for?
  • no, it would simply be a numerical index... I need something to target the html element
  • @SimonQuest This answer (and subsequent) may help you.