如何以 RESTful 方式公开验证 API?

我通常是 RESTful API 设计的粉丝,但我不确定如何将 REST 原则应用于验证 API。

假设我们有一个用于查询和更新用户配置文件信息(名称、电子邮件、用户名和密码)的 API。我们认为公开的一个有用的功能是验证,例如查询给定的用户名是否有效和可用。

在这种情况下,资源是什么? 应该使用什么 HTTP 状态代码和/或头?

首先,我有 GET /profile/validate,它接受查询字符串参数,如果有效或无效,返回 204400。但是 validate显然是一个动词而不是名词。

52992 次浏览

您所描述的类型在语义上当然更像 RPC 风格,但这并不意味着您不能以 RESTful 方式实现目标。

没有 VALIDATE HTTP 动词,那么围绕它构造整个 API 能获得多少价值呢?您的故事围绕着向用户提供确定给定用户名是否可用的能力展开——在我看来,这听起来像是一个简单的资源检索检查—— GET: /profile/username/...——如果结果是404,那么该名称是可用的。

这突出表明,客户端验证只是客户端验证。确保数据在发送到服务器之前在客户机上进行验证是一个 UI 问题。RESTful 服务并不关心客户机是否执行了验证; 它只是根据自己的验证逻辑接受或拒绝请求。

REST 并不是一个包罗万象的范例,它只是描述了一种构建客户机-服务器通信的方法。

您将 REST 与面向资源混淆了,REST 中没有任何内容说明您不能在 URL 中使用动词。说到 URL 设计,我通常会选择自我描述性最强的,无论是名词还是动词。

关于您的服务,我将使用您用于更新的相同资源,但使用 test querystring 参数,因此当 test=1操作没有完成,但您可以使用它返回验证错误。

PATCH /profile?test=1
Content-Type: application/x-www-form-urlencoded


dob=foo

回答是:

HTTP/1.1 400 Bad Request
Content-Type: text/html


<ul class="errors">
<li data-name="dob">foo is not a valid date.</li>
</ul>

我们也遇到了同样的问题。我们让客户机遵从服务器进行验证的原因是为了防止出现不匹配的规则。服务器需要在对资源进行操作之前验证所有内容。对这些规则进行两次编码并使它们失去同步的可能性是没有意义的。因此,我们提出了一种似乎与 REST 思想保持一致的策略,同时允许我们请求服务器执行验证。

我们的第一步是实现可以从元数据服务(GET /metadata/user)请求的元数据对象。然后使用这个元数据对象告诉客户端如何执行基本的客户端验证(需求、类型、长度等)。我们从数据库中生成其中的大部分。

第二部分包括添加一个称为分析的新资源。例如,如果我们有一个服务:

GET /users/100

我们将创建一个新的资源,名为:

POST /users/100/analysis

分析资源不仅包含所发生的任何验证错误,还包含在需要时可能相关的统计信息。我们讨论过的问题之一是用哪个动词作为分析资源。我们的结论是,它应该是一个 POST,因为分析是在请求时创建的。然而,GET 也有强有力的论据。

我希望这对其他试图解决同样问题的人有所帮助。任何关于这个设计的反馈都是值得赞赏的。

在 RESTAPI 中进行验证非常好。无论如何,您需要一个验证,并且为什么不在客户端使用它。在我的例子中,我只是在 API 中有一个约定,即一个特殊的 error _ id 表示验证错误,在 error _ Details 中,对于在这个 PUT 或 POST 调用中有错误的每个字段,都有一个错误消息数组。例如:

{
"error": true,
"error_id": 20301,
"error_message": "Validation failed!",
"error_details": {
"number": [
"Number must not be empty"
],
"ean": [
"Ean must not be empty",
"Ean is not a valid EAN"
]
}
}

如果您对 Web 和移动应用程序使用相同的 REST API,那么您将喜欢仅通过更新 API 来改变两者的验证的能力。特别是手机更新需要超过24小时才能在商店上发布。

这是它在移动应用程序中的样子: enter image description here

PUT 或 POST 的响应用于显示每个字段的错误消息。这是来自使用 React 的 Web 应用程序的相同调用: enter image description here

这样,所有 RESTAPI 响应代码(如200、404)都应该有自己的含义。即使验证失败,PUT 调用响应也是200。如果调用通过了验证,响应应该是这样的:

{
"error": false,
"item": {
"id": 1,
"created_at": "2016-08-03 13:58:11",
"updated_at": "2016-11-30 08:55:58",
"deleted_at": null,
"name": "Artikel 1",
"number": "1273673813",
"ean": "12345678912222"
}
}

你可以做一些可能的修改。可以使用它而不使用 error _ id。如果有 error _ Details,只需循环它们,如果您找到一个与字段名相同的键,则将其值作为错误文本放到同一个字段中。

一个非常常见的场景是,用户或配置文件注册表单的用户名和电子邮件应该是唯一的。错误信息通常会显示在文本框的模糊处,让用户知道用户名已经存在,或者他们输入的电子邮件已经与另一个帐户关联。其他答案中提到了很多选项,但我不喜欢需要查找404表示用户名不存在的想法,因此它是有效的,等待提交来验证整个对象,并且返回验证元数据无助于检查唯一性。

依莫,应该有一个 GET 路由,每个需要验证的字段返回 true 或 false。

/users/validation/username/{username}

还有

/users/validation/email/{email}

您可以使用此模式为需要服务器端验证的任何其他字段添加任何其他路由。当然,您仍然希望在 POST 中验证整个对象。

此模式还允许在更新用户时进行验证。如果用户将注意力集中在邮件文本框上,然后点击开启模糊验证,稍微不同的验证将是必要的,因为如果邮件已经存在,只要它与当前用户关联。您可以利用这些同样返回 true 或 false 的 GET 路由。

/users/{userId:guid}/validation/username/{username}

还有

/users/{userId:guid}/validation/email/{email}

同样,整个对象需要在 PUT 中进行验证。