如何处理REST POST的无效表单?

时间:2022-05-30 00:20:56

I am developing a website that offers a REST service. All the GET actions are OK and rendered using a .json.twig template, but I am having a hard time understanding how to output form errors if the query made to create a new record is not valid. If I try to do a simple

我正在开发一个提供REST服务的网站。所有GET操作都可以使用.json.twig模板进行渲染,但是如果用于创建新记录的查询无效,我很难理解如何输出表单错误。如果我尝试做一个简单的

return $form;

I get the following exception from SF:

我从SF获得以下异常:

"exception":[{"message":"Unable to find template \"SomeBundle:Customers:postCustomer.json.twig\"}]

“exception”:[{“message”:“无法找到模板”SomeBundle:Customers:postCustomer.json.twig \“}]

The template does not exist, that's true, but I have no idea how to create one in JSON format to tell the requestor that his query is incomplete / malformed.

模板不存在,这是真的,但我不知道如何用JSON格式创建一个模板来告诉请求者他的查询是不完整/格式错误的。

If I try anything else dealing with views but without specifying a template, the result is the same. Is there a way to do that automatically so that if the form is modified the change are reflected as well in the error ? Or a way to tell FOSRestBundle / JMSSerializerBundle to deal with the serialization themselves ? Before switching to Twig responses the error was nicely handled, and I'd like to have that back, along with the Twig templates for normal operations.

如果我尝试处理视图但没有指定模板的任何其他内容,结果是相同的。有没有办法自动执行此操作,以便在修改表单时,更改也会反映在错误中?或者告诉FOSRestBundle / JMSSerializerBundle自己处理序列化的方法?在切换到Twig响应之前,错误得到了很好的处理,我希望能够将其与正常操作的Twig模板一起使用。

For information, my current controller's action is:

有关信息,我当前控制器的操作是:

/**
 * @ApiDoc(
 *      resource=false,
 *      input="SomeBundle\Form\CustomerType",
 *      description="Create a new customer",
 *      section="Customers",
 *      statusCode={
 *          201="Action successful",
 *          403="Authorization required but incorrect / missing information or insufficient rights",
 *          500="Returned if action failed for unknown reasons"
 *      }
 *  )
 *
 * --View(template="SomeBundle:Customers:add.json.twig", templateVar="form", statusCode=400)
 * @View(templateVar="form", statusCode=400)
 * @param Request $request
 * @return \FOS\RestBundle\View\View
 */
    public function postCustomerAction(Request $request) {
        $data = json_decode($request->getContent(), true);
        $manager = $this->getManager();
        $customer = new Customer();
        $form = $this->getForm($customer);
        //$form->submit($data);
        //$manager->create($customer);

//        $form->handleRequest($request);
//        if ($form->isSubmitted() && $form->isValid()) {
//            $manager->create($customer);
//
//            return $this->redirectView($this->generateUrl('api_get_customer_internal', ['uuid' => $customer->getInternalUuid()], true),
//                                       201);
//        }

        return $form;
        //return $this->handleView($this->view($form, 400));
        //return \FOS\RestBundle\View\View::create($form, 400);
    }

And the FOSRestBundle configuration:

和FOSRestBundle配置:

fos_rest:
  param_fetcher_listener: true
  body_listener: true
  format_listener:
    enabled: true
  view:
    view_response_listener: 'force'
    formats:
      json: true
    templating_formats:
        json: true
    force_redirects:
      html: true
    failed_validation: HTTP_BAD_REQUEST
    default_engine: twig
  routing_loader:
    include_format: false
    default_format: json
  serializer:
    serialize_null: true

sensio_framework_extra:
  view:
    annotations: true

1 个解决方案

#1


0  

Thanks to jorge07 at https://github.com/FriendsOfSymfony/FOSRestBundle/issues/1620 I was able to find a way to circumvent that in a rather proper way (at least IMHO), here's the updated Controller action (no change in the fosrestbundle settings required):

感谢jorge07在https://github.com/FriendsOfSymfony/FOSRestBundle/issues/1620,我能够找到一种方法以一种相当正确的方式绕过它(至少恕我直言),这里是更新的控制器动作(没有改变需要fosrestbundle设置):

/**
 * @Route("/customers")
 * @ApiDoc(
 *      resource=false,
 *      input="NetDev\CoreBundle\Form\CustomerType",
 *      description="Create a new customer",
 *      section="Customers",
 *      statusCode={
 *          201="Action successful",
 *          403="Authorization required but incorrect / missing information or insufficient rights",
 *          500="Returned if action failed for unknown reasons"
 *      }
 *  )
 *
 * @View(template="NetDevRestBundle:Common:form_error.json.twig", templateVar="errors", statusCode=400)
 *
 * @RequestParam(name="customerName", nullable=false)
 * @RequestParam(name="customerIndex", nullable=false)
 *
 * @return \FOS\RestBundle\View\View
 */
public function postCustomerAction(ParamFetcher $fetcher)
{
    $customer = new Customer();
    $form = $this->getForm($customer);
    $form->submit($fetcher->all(), true);

    if ($form->isValid()) {
        $manager = $this->getManager();
        $manager->create($customer);

        return $this->redirectView($this->generateUrl('api_get_customer_internal', ['uuid' => $customer->getInternalUuid()], true), 201);
    }

    $err = $form->getErrors();
    $errorsList = [];
    foreach ($err as $it) {
        $errorsList[(string)$it->getOrigin()->getPropertyPath()] = $it->getMessage();
    }

    return $this->view([$errorsList])
        ->setTemplateVar('errors')
        ;
}

#1


0  

Thanks to jorge07 at https://github.com/FriendsOfSymfony/FOSRestBundle/issues/1620 I was able to find a way to circumvent that in a rather proper way (at least IMHO), here's the updated Controller action (no change in the fosrestbundle settings required):

感谢jorge07在https://github.com/FriendsOfSymfony/FOSRestBundle/issues/1620,我能够找到一种方法以一种相当正确的方式绕过它(至少恕我直言),这里是更新的控制器动作(没有改变需要fosrestbundle设置):

/**
 * @Route("/customers")
 * @ApiDoc(
 *      resource=false,
 *      input="NetDev\CoreBundle\Form\CustomerType",
 *      description="Create a new customer",
 *      section="Customers",
 *      statusCode={
 *          201="Action successful",
 *          403="Authorization required but incorrect / missing information or insufficient rights",
 *          500="Returned if action failed for unknown reasons"
 *      }
 *  )
 *
 * @View(template="NetDevRestBundle:Common:form_error.json.twig", templateVar="errors", statusCode=400)
 *
 * @RequestParam(name="customerName", nullable=false)
 * @RequestParam(name="customerIndex", nullable=false)
 *
 * @return \FOS\RestBundle\View\View
 */
public function postCustomerAction(ParamFetcher $fetcher)
{
    $customer = new Customer();
    $form = $this->getForm($customer);
    $form->submit($fetcher->all(), true);

    if ($form->isValid()) {
        $manager = $this->getManager();
        $manager->create($customer);

        return $this->redirectView($this->generateUrl('api_get_customer_internal', ['uuid' => $customer->getInternalUuid()], true), 201);
    }

    $err = $form->getErrors();
    $errorsList = [];
    foreach ($err as $it) {
        $errorsList[(string)$it->getOrigin()->getPropertyPath()] = $it->getMessage();
    }

    return $this->view([$errorsList])
        ->setTemplateVar('errors')
        ;
}