Symfony + API 平台:当 POST 数据具有意外(例如输入错误)的属性时,有没有办法抛出错误?

Symfony + API Platform: Is there a way to throw an error when POST data has unexpected (eg. mistyped) properties?

假设我有一个名为“Foo”的 API 资源和 属性 “bar”,我使 POST 操作可用于创建一个新实例:

POST /api/foo
{
   "bar": "whatever"
}

如果我的 API 用户错误输入 属性,如下所示:

POST /api/foo
{
   "bat": "whatever"
}

没有错误。

我可以在 属性“bar”上添加 NotNull 约束,这样如果“bar”不包含在内,就会抛出错误,但是如果“bar”可以为 null 怎么办?现在的结果是“bar”变为 NULL,这不是最终用户所期望的。

或者,如果添加任何其他属性,则不会引发错误或警告,例如,如果“发布”不是 属性 但提交了以下内容:

POST /api/foo
{
   "bar": "whatever",
   "publish": true
}

没有关于意外“发布”的错误或警告属性。最终用户可能希望此 属性 可用,可能是因为它存在于其他资源上,但响应中没有错误。显然最终用户应该阅读文档,但我更愿意直接在响应中提供反馈以确保 100% 合规。

总结: 如果我的 API 的用户添加了错误的属性,或者不小心输入了错误的 属性 名称,我该如何检测并抛出错误?

您可以将@Groups 注释与denormalization_context 一起使用。因此,您声明了被授予更新的属性。并使用强类型提示

<?php

declare(strict_types=1);

namespace AppBundle\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;

/**
 * Class Foo
 * @package AppBundle\Entity
 * @ORM\Entity()
 * @ORM\Table()
 * @ApiResource(
 *  attributes={
 *      "normalization_context"={"groups"={"get"}},
 *      "denormalization_context"={"groups"={"put, "post"}}
 *  },
 *  itemOperations={},
 *  collectionOperations={"post"}
 * ) 
 */
class Foo
{
    /**
     * @var string 
     * @ORM\Column(name="bar", type="string", nullable=false) 
     * @Groups({"get", "post"}) 
     */
    private string $bar;

    /**
     * @var string
     * @ORM\Column(name="bar", type="string", nullable=false)
     * @Groups({"get"}) 
     */
    private string $bat;

    /**
     * @var bool 
     * @ORM\Column(name="public", type="boolean", nullable=false)
     * @Groups({"get", "post"})
     */
    private bool $public;

    /**
     * @return string
     */
    public function getBar(): string
    {
        return $this->bar;
    }

    /**
     * @param string $bar
     *
     * @return Foo
     */
    public function setBar(string $bar): Foo
    {
        $this->bar = $bar;
        return $this;
    }

    /**
     * @return string
     */
    public function getBat(): string
    {
        return $this->bat;
    }

    /**
     * @param string $bat
     *
     * @return Foo
     */
    public function setBat(string $bat): Foo
    {
        $this->bat = $bat;
        return $this;
    }

    /**
     * @return bool
     */
    public function isPublic(): bool
    {
        return $this->public;
    }

    /**
     * @param bool $public
     *
     * @return Foo
     */
    public function setPublic(bool $public): Foo
    {
        $this->public = $public;
        return $this;
    }
}

您可以看到 属性 $bat 没有组注释“post”:因此您的 POST 请求中未授权此字段。您也可以添加一些约束:例如:

use Symfony\Component\Validator\Constraint as Assert;

//...
    /**
     * @var string
     * @ORM\Column(name="bar", type="string", nullable=false)
     * @Groups({"get", "post"})
     * @Assert\NotBlank(message="property bar is mandatory")
     */
    private string $bar;

希望对您有所帮助。

我意识到这与反规范化步骤有关,最终发现:

/**
 * @ApiResource(
 *     denormalizationContext={"allow_extra_attributes"=false}
 * )
 */

参考:https://github.com/api-platform/core/issues/1217#issuecomment-488662805