繁体   English   中英

如何使用FOSRest和Symfony 3.0正确执行REST API POST调用

[英]How to properly do a REST API POST call using FOSRest and Symfony 3.0

对于我当前正在构建的API,我希望能够发送带有以下内容的JSON正文的请求

{"title": "foo"}

为名为Project的实体创建新的数据库记录。

我做了一个子类FOSRestController的控制器。 为了创建一个项目,我做了一个动作

/**
 * @Route("/")
 *
 * @ApiDoc(
 *     section="Project",
 *     resource=true,
 *     input={"class"="AppBundle\Form\API\ProjectType"},
 *     description="Creates a new project",
 *     statusCodes={
 *         201="Returned when successful",
 *      }
 * )
 *
 * @Method("POST")
 * @Rest\View(statusCode=201)
 */
public function createProjectAction(Request $request)
{
    $project = new Project();
    $form = $this->createForm(ProjectType::class, $project);
    $form->submit(($request->request->get($form->getName())));

    if ($form->isSubmitted() && $form->isValid()) {
        return $project;
    }

    return View::create($form, 400);
}

ProjectType看起来像这样

class ProjectType extends AbstractType {
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('title');
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'AppBundle\Entity\Project'
        ));
    }
}

但是,当我尝试将上述JSON发布到API时,它会响应title属性不能为空,这很好,因为这是为其设置的验证规则。 但是,它已设置。 我突然意识到我必须发送以实际对象名称为前缀的JSON才能完成此工作:

{"project":{"title": "bla"}}

公平地说,这有点奇怪,仅发布属性就足够了。

因此,基于此信息,我仅有两个问题:

  1. 为什么我需要使用($request->request->get($form->getName())) “提交”此表单,所以$request不够吗?
  2. 我需要为FormType更改什么以按原样验证实体,而不是在实体名称前添加前缀?

编辑1:在“默认选项”中添加或删除data_class根本不会更改行为。

这是因为Symfony Controller“ createForm”帮助器方法的工作方式。 其背后的原因是多种形式可能具有相同的目标URL。 通过以表单名称作为前缀,Symfony可以知道提交的表单。

通过查看“ createForm”方法的实现可以看出:

public function createForm($type, $data = null, array $options = array())
{
    return $this->container->get('form.factory')->create($type, $data, $options);
}

如果您不希望出现这种情况,则更改它确实很容易:

public function createProjectAction(Request $request)
{
    $project = new Project();
    $form = $this->get('form.factory')->createNamed(null, new ProjectType(), $project);
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {
        return $project;
    }

    return View::create($form, 400);
}

因此,您基本上是在创建“无名”表单。 由于您正在构建API,因此最好将其放入基本控制器的createNamelessForm($type, $data, $options)帮助器方法中,这样就不必从容器中显式地获取Form Factory了。时间,让眼睛更轻松。

评论您的编辑

包装器密钥不是由“ data_class”选项生成的,而是由表单类型上的“ getName()”方法生成的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM