API 平台 DTO 验证器 - 缺少属性并不违规

问题描述 投票:0回答:1

我有一个 API Platform DataTransformer,它使用注入的 ValidatorInterface 来验证传入请求的 JSON POST 正文。它基本上是 docs:

中示例的副本
<?php

namespace App\DataTransformer;

use ApiPlatform\Core\Validator\ValidatorInterface;
use ApiPlatform\Core\DataTransformer\DataTransformerInterface;
use App\Entity\Ticket;
use App\DTO\TicketInput;

class InputDataTransformer implements DataTransformerInterface
{
    public function __construct(
        private readonly ValidatorInterface $validator,
    ) {}

    /**
     * @param TicketInput $object
     */
    public function transform($object, string $to, array $context = []): Ticket
    {
        // Validation
        $this->validator->validate($object);

        $ticket = new Ticket($object->id, $object->content);
        return $ticket;
    }

    public function supportsTransformation($data, string $to, array $context = []): bool
    {
        return (Ticket::class === $to) && (($context['input']['class'] ?? null) === TicketInput::class);
    }
}

通过 ContextBuilder 和

supportsTransformation()
,我确保传入的
$object
属于 TicketInput 类型。这堂课就是这么简单:

<?php

namespace App\DTO;

class TicketInput
{
    public int $id;
    public ?string $content;
}

我想知道的是:验证器通过

TicketInput::class
验证
$id
必须是整数并且不可为空。
$content
必须是字符串,且允许为空。

所以这些是有效输入:

{
    "id": 123,
    "content": null
},
{
    "id": 123,
    "content": "testtest"
}

这是无效并被拒绝(400 - 错误请求):

{
    "id": null,
    "content": "foobar"
}

到目前为止一切顺利。但我的一个单元测试使用此 JSON 作为请求正文:

{
    "content": "foobar"
}

这破坏了我的代码,因为

$id
是结果
Ticket::class
的必需值。

我非常惊讶最后一个案例能够通过验证器,因为我在

$id
中明确将
TicketInput::class
定义为(不可为空)类变量。有人可能会争辩说,验证器没有义务在验证时验证“未初始化”的属性(根据 var_dump,这里就是这种情况),但尽管如此,我还是对如何定义该属性是
mandatory 感兴趣。 
并且必须是 JSON POST 正文的一部分。 我能想到的最好的办法是 Symfony 验证约束

#[Assert\NotBlank(allowNull: false)]

(参见

docs
),它检查 is_null() 并间接检查
isset()
,但我不敢相信这就是解决方案,而且我已经像这样标记每个属性(实际的
TicketInput::class
比这个MWE更大更复杂)。
是否没有任何验证器配置标志告诉它确保 DTO 中的属性在 JSON 正文中是强制性的?

每个简单的 JSON 模式验证器都能够做到这一点,我想知道为什么我在 Symfony 文档或 API 平台文档中都没有找到任何提示。

symfony validation api-platform.com symfony-validator
1个回答
0
投票

PATCH

方法允许仅发送您想要更新的字段,而

PUT
方法则需要整个数据都在那里。因此,根据方法,我想使用相同的 DTO 对象,但仅允许验证发送的字段。
    

© www.soinside.com 2019 - 2024. All rights reserved.