Published on

Api platform教程13--错误处理

原创文章,转载时需取得本人同意并注明来源
Authors
  • Api platform教程13--错误处理
    Name
    langziyang
    Twitter

我们在使用symfony时,可能会在Entity里对字段进行验证,比如说对身份证进行18位长度验证

#[Assert\Length(min: 18, max: 18, exactMessage: '身份证不正确')]
private ?string $idNumber = null;

此时假如我们post一条数据,idNumber小于或者大于18位,api platform会返回一条错误信息:

{
	"@id": "\/api\/errors\/422",
	"@type": "hydra:Error",
	"title": "An error occurred",
	"detail": "idNumber: 身份证不正确",
	"status": 422,
	"type": "\/errors\/422",
	"trace": [],
	"hydra:title": "An error occurred",
	"hydra:description": "idNumber: 身份证不正确"
}

我们可以看到hydra:description字段提示了字段名和错误消息,对于开发者来说这是非常方便的,因为可以一目了然的知道是哪一个字段出错。但是在生产环境我们只需要给用户提示身份证不正确即可,不需要把字段名也显示给用户。那么我们如何处理呢?

根据api platform文档说明,验证错误有一个专属错误provider: api_platform.validator.state.error_provider

所以你可以自定义这个服务,有两种方式:一种是在services.yaml中对服务进行定义;如果你看过我以前的教程,你可能会记得有一个名为装饰服务的东西,没错,这比在services.yaml中定义更方便:

<?php

namespace App\State\Common\Provider;

use ApiPlatform\Metadata\HttpOperation;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ApiResource\Error;
use ApiPlatform\State\ProviderInterface;
use Symfony\Component\DependencyInjection\Attribute\AsDecorator;
use Symfony\Component\DependencyInjection\Attribute\AutowireDecorated;
use function Symfony\Component\String\u;

#[AsDecorator('api_platform.validator.state.error_provider')]
final class ErrorProvider implements ProviderInterface
{
    public function __construct(
        #[AutowireDecorated]
        private $inner
    )
    {
    }

    public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
    {
        $exception = $this->inner->provide($operation, $uriVariables, $context);
        /** @var HttpOperation $operation */
        $status = $operation->getStatus() ?? 500;
        // You don't have to use this, you can use a Response, an array or any object (preferably a resource that API Platform can handle).
        $error = Error::createFromException($exception, $status);

        // care about hiding informations as this can be a security leak
        if ($status >= 500) {
            $error->setDetail('Something went wrong');
        }
        if ($_ENV['APP_ENV'] === 'prod') {
            $detail = u($error->getDetail());
            $error->setDetail($detail->slice($detail->indexOfLast(':') + 1)->trim());
        }
        return $error;
    }
}

可以看到我们使用一句

#[AsDecorator('api_platform.validator.state.error_provider')]

就完成了整个服务的重写。 同时,我们在构造函数里写了

#[AutowireDecorated]

这样我们就可以在provide方法里通过

$exception = $this->inner->provide($operation, $uriVariables, $context);

取得被装饰服务里的返回数据.

再次提交,是否只显示了错误消息?当然,在这里你也可以通过APP_ENV来判断,如果是生产坏境才处理。