在哪里验证发送给API的参数?



在API设计中验证用户发送的参数的最佳实践是什么?通过参数验证,我指的是:检查所需的参数是否发送,确保它们具有正确的格式,等等……下面是验证已发送id的几个简单示例。下面是Python使用Flask的例子:

A)在路由定义中添加验证逻辑,在控制器中。
@api.route('/job', methods=['GET'])
def get_jobs():
try:
if params["id"] is None:
raise Exception("Invalid param ID parameters.")
job = job_manager.get_job(params["id"])
return jsonify(job)

B)在应用程序的核心。这是业务层,在这里应用逻辑来转换数据。

class JobManager:
def get_job(self, job_id) -> None:
if job_id is None:
raise Exception("Invalid param ID parameters.")

在更复杂的场景中,可以使用validator服务或装饰器,但问题是相同的:在代码的哪一点是验证用户输入的最佳实践。

如果答案是以上任何一种情况(或两者都有),请提供更多详细的答案。如果可能的话,尽量成为语言不可知论,因为我正在寻找一个可以应用于任何地方的最佳实践。

解析通常应该在信息进入系统时进行,或者尽可能接近这个点。

因此当然&;应用层&;而不是"域层/业务层":要么由控制器本身调用,要么非常接近它。(不是典型的"in";控制器,因为您应该能够测试解析器,而无需耦合到一堆HTTP仪式。

@api.route('/job', methods=['GET'])
def get_jobs():
try:
job_id = parse_job_id(params["id"])
job = job_manager.get_job(job_id)
return jsonify(job)

在类型语言中,这可以使您的工作轻松得多,因为您大大减少了需要询问"这个通用数据结构是否包含我期望的信息"的地方。

另一方面,对业务策略的检查通常属于域层。

例如:如果你的API需要一个日期,它会检查这个日期是否实际存在,以及这个日期是否以合适的ISO-8601格式表示,等等…这些类型的检查都是控制器解析输入的一部分。

另一方面,检查日期是否"将来",或者日期是否在保修期内,或者……这些检查属于您的域代码。

通常,我将验证分为几个阶段:

  1. REST控制器中输入数据的即时语法验证
  2. 服务中的业务逻辑验证

第一个验证应该只标记那些绝对错误的东西;例如,缺少必需的字段,类型不匹配,无法解析的字符串,任何代码注入的尝试以及安全令牌的存在(或缺乏)。

当此验证通过时,输入数据至少在语法上是正确的,并且可以传递给服务,在那里发生更严格的验证;例如,输入数据在业务方面是否有意义,具有该ID的资源是否存在-等等。

简短版本:第一个验证查找明显错误的内容,而接下来的验证确保输入数据正确且具有业务意义。

最新更新