如何处理 REST POST 的无效表单?
How to handle invalid forms for a REST POST?
我正在开发一个提供 REST 服务的网站。所有 GET 操作都可以并使用 .json.twig 模板呈现,但我很难理解如果创建新记录的查询无效时如何输出表单错误。
如果我尝试做一个简单的
return $form;
我从 SF 收到以下异常:
"exception":[{"message":"Unable to find template \"SomeBundle:Customers:postCustomer.json.twig\"}]
模板不存在,这是真的,但我不知道如何创建一个 JSON 格式的模板来告诉请求者他的查询不完整/格式错误。
如果我尝试任何其他处理视图但未指定模板的方法,结果都是一样的。有没有一种方法可以自动执行此操作,以便如果修改了表单,更改也会反映在错误中?
或者告诉 FOSRestBundle/JMSSerializerBundle 自己处理序列化的方法?在切换到 Twig 响应之前,错误得到了很好的处理,我想把它连同用于正常操作的 Twig 模板一起恢复。
供参考,我当前控制器的操作是:
/**
* @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);
}
以及 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
感谢 https://github.com/FriendsOfSymfony/FOSRestBundle/issues/1620 的 jorge07,我找到了一种以相当恰当的方式(至少恕我直言)规避该问题的方法,这是更新后的控制器操作(无需更改 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')
;
}
我正在开发一个提供 REST 服务的网站。所有 GET 操作都可以并使用 .json.twig 模板呈现,但我很难理解如果创建新记录的查询无效时如何输出表单错误。 如果我尝试做一个简单的
return $form;
我从 SF 收到以下异常:
"exception":[{"message":"Unable to find template \"SomeBundle:Customers:postCustomer.json.twig\"}]
模板不存在,这是真的,但我不知道如何创建一个 JSON 格式的模板来告诉请求者他的查询不完整/格式错误。
如果我尝试任何其他处理视图但未指定模板的方法,结果都是一样的。有没有一种方法可以自动执行此操作,以便如果修改了表单,更改也会反映在错误中? 或者告诉 FOSRestBundle/JMSSerializerBundle 自己处理序列化的方法?在切换到 Twig 响应之前,错误得到了很好的处理,我想把它连同用于正常操作的 Twig 模板一起恢复。
供参考,我当前控制器的操作是:
/**
* @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);
}
以及 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
感谢 https://github.com/FriendsOfSymfony/FOSRestBundle/issues/1620 的 jorge07,我找到了一种以相当恰当的方式(至少恕我直言)规避该问题的方法,这是更新后的控制器操作(无需更改 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')
;
}