解决接口用map接收客户端参数的方案

引出问题,代码如下:

<?php

declare(strict_types=1);

namespace App\Controller;

use App\Services\RegisterService;
use Hyperf\Context\ApplicationContext;
use Hyperf\Validation\Contract\ValidatorFactoryInterface;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;

class IndexController extends AbstractController
{
    /**
     * 注册用户
     * @return array
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    public function index(): array
    {
        $data = $this->request->all();
        $validator = ApplicationContext::getContainer()->get(ValidatorFactoryInterface::class)->make(
            $data,
            [
                'account' => 'required|string',
                'password' => 'required|string',
                'verification_code' => 'required|string',
            ],
        );
        if ($validator->fails()) {
            return [
                'code' => 1,
                'message' => $validator->getMessageBag()->first(),
            ];
        }
        $data = $validator->validated();
        return [
            'code' => 0,
            //create方法接收一个data,data里面有什么东西,编辑器是不知道的
            'data' => RegisterService::create($data),
            'message' => '注册成功',
        ];
    }
}

上面的代码中RegisterService::create的入参是一个map,里面有什么东西,编辑器无法识别。

我解决方案是,用一个类去描述需要的参数,类的成员属性的校验规则用注解进行描述。
上的代码,可以写成:

<?php

namespace App\Arg;

use Arg\ArgAttr;
use Arg\BaseArg;

/**
 * 注册一个用户
 */
class RegisterArg extends BaseArg
{
    /**
     * @var string 账号
     */
    #[ArgAttr('required')]
    #[ArgAttr('string')]
    public string $account;

    /**
     * @var string 密码
     */
    #[ArgAttr('required')]
    #[ArgAttr('string')]
    public string $password;

    /**
     * @var string 验证码
     */
    #[ArgAttr('required')]
    #[ArgAttr('string')]
    public string $verification_code;
}
<?php

declare(strict_types=1);

namespace App\Controller;

use App\Arg\RegisterArg;
use App\Services\RegisterService;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;

class IndexController extends AbstractController
{
    /**
     * 注册用户
     * @return array
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    public function index(): array
    {
        //初始化参数类
        $registerArg = new RegisterArg();
        //获取客户端发送的数据
        $data = $this->request->all();
        //校验数据
        $msgBag = $registerArg->validate($data);
        if ($msgBag->isNotEmpty()) {
            //校验失败,返回错误信息
            return [
                'code' => 1,
                'message' => $msgBag->first(),
            ];
        }
        //校验成功,将客户端数据注入到参数对象中
        $registerArg->assign($data);
        //调用service层的注册逻辑,执行注册动作,并返回注册结果
        return [
            'code' => 0,
            'data' => RegisterService::create($registerArg),
            'message' => '注册成功',
        ];
    }
}

项目地址:github.com/buexplain/arg

本作品采用《CC 协议》,转载必须注明作者和本文链接
梦想星辰大海
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 2

想要优雅点儿,肯定是需要定义成单独的 Data 类,不过一般可以用一些现成的包来做,比如 Laravel-Data,就是需要一些适应。

如果只是简单的想要提示,也可以考虑使用注释,使用 array-shape

3个月前 评论
梦想星辰大海 (楼主) 3个月前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!