controller和service都有参数校验需求,应该怎样设计?

按照网上的说法

controller应该校验与业务无关的数据,如字符串长度/手机号/email的格式
service只校验和业务相关的,如用户是否存在,库存是否足够等

但是我的service会在多个地方调用,可能其他人在调用的时候并不清楚参数的格式,给了错误的参数,那报错就成了一堆sql了
所以我希望在任何情况下,service都能给出具体的错误。

那这样我controller校验一次,service又校验一次,还都是相同的规则,这不重复了吗?
可是如果controller不做校验的话,好像又不太对

想问问大佬们这种情况下应该怎么设计,或者大家是怎么写的?


还看到这样一句话,这句话说的对吗?我有点不太能接受

校验应该放在 controller 层,到了 service 应该假设参数都是完整且合规的。


谢谢大家,每个人的留言都对我很有用,我全部点赞了,大家说的我都听进去了,我会参考的,感谢:grin:

《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
陈先生
最佳答案

可能其他人在调用的时候并不清楚参数的格式,给了错误的参数

我们不必为别人的愚蠢负责

前提是你写好了对应的注释和结构,原本一个注释就可以解决的问题,为什么要搞得这么麻烦。

其次 如果你考虑抽象封装,那就加一个 DataTransfer,你 Service 接到的是一个 DataTransfer,并不是单独的数据,直接,验证逻辑完全交由 DataTransfer 来做。将职责清晰划分后,就明了多了。职责如下

  1. Controller 接受数据
  2. Controller 组装数据并生成 DataTransfer
  3. DataTransfer Validate
  4. 调用 Service 并传入 Transfer

EX:


use ExampleDataTransfer;
use ExampleService;

class ExampleController extends Controller
{
    public function test(Request $request, ExampleService $service)
    {
        // Choose 1
        // You can handle other logic through the request or others on this step
        // other ligic begin
        //todo handle other logic
        // other ligic finished
        $data_transfer = new ExampleDataTransfer($request->all());
        $data_transfer->validate(); // Throw the ValidationException if failed
        // Choose 1
        $service->transfer = $data_transfer;
        $service->callMethod();
        //Choose 2
        $service->callMethod($data_transfer);
    }
}
1年前 评论
陈先生 (作者) 1年前
leven5 (楼主) 1年前
讨论数量: 10

service 要考虑的是可以在多个地方复用,大多开源的项目 service 都不是这样考虑的。看项目情况吧

1年前 评论

你要是多处调用service最好是方法兼容 而不是service使用验证

1年前 评论
陈先生

可能其他人在调用的时候并不清楚参数的格式,给了错误的参数

我们不必为别人的愚蠢负责

前提是你写好了对应的注释和结构,原本一个注释就可以解决的问题,为什么要搞得这么麻烦。

其次 如果你考虑抽象封装,那就加一个 DataTransfer,你 Service 接到的是一个 DataTransfer,并不是单独的数据,直接,验证逻辑完全交由 DataTransfer 来做。将职责清晰划分后,就明了多了。职责如下

  1. Controller 接受数据
  2. Controller 组装数据并生成 DataTransfer
  3. DataTransfer Validate
  4. 调用 Service 并传入 Transfer

EX:


use ExampleDataTransfer;
use ExampleService;

class ExampleController extends Controller
{
    public function test(Request $request, ExampleService $service)
    {
        // Choose 1
        // You can handle other logic through the request or others on this step
        // other ligic begin
        //todo handle other logic
        // other ligic finished
        $data_transfer = new ExampleDataTransfer($request->all());
        $data_transfer->validate(); // Throw the ValidationException if failed
        // Choose 1
        $service->transfer = $data_transfer;
        $service->callMethod();
        //Choose 2
        $service->callMethod($data_transfer);
    }
}
1年前 评论
陈先生 (作者) 1年前
leven5 (楼主) 1年前

总的来说,在控制器层和在服务层校验我觉得都可以,但是我自己的项目都是在控制器层验证的。

Larave也设计了专门的校验类,注入到控制器中,我觉得还是挺方便的,但是简单的校验我也不写专门的校验类,比如只有一个参数而且判断也很简单,我就直接写控制器里。

写控制器的好处就是:服务层那里不需要再做校验了。

1年前 评论
巅峰互联

只需要关心 controller 数据校验,校验完的数据才会流转到service 服务中。 业务数据,业务层处理,服务层数据只是为了复用封装。

1年前 评论
陈先生 1年前
巅峰互联 (作者) 1年前

file

把你需要的业务条件在service判断一下,不存在抛异常。不应该走到sql层报错的,只要你的异常抛的正确,复用该service的才能根据错误进行修正。

1年前 评论

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