我通常是RESTful API设计的粉丝,但我不确定如何将REST原则应用于验证API。
假设我们有一个用于查询和更新用户个人资料信息(名称,电子邮件,用户名,密码)的API。我们认为公开的有用功能将是验证,例如查询给定的用户名是否有效且可用。
在这种情况下有哪些资源?应该使用哪些HTTP状态代码和/或标头?
首先,我GET /profile/validate
接受查询字符串参数,如果有效或无效,则返回204
或400
。但validate
显然是动词,而不是名词。
答案 0 :(得分:41)
你所描述的东西在其语义中肯定更像RPC风格,但这并不意味着你无法以RESTful方式实现目标。
没有VALIDATE
HTTP动词,那么围绕该动词构建整个API可以获得多少价值?您的故事围绕为用户提供了确定给定用户名是否可用的能力 - 听起来像是一个简单的资源检索检查 - GET: /profile/username/...
- 如果结果是404,则名称可用。
这突出表明客户端验证就是客户端。确保在发送到服务器之前在客户端上验证数据是一个UI问题。 RESTful服务不会判断客户端是否已执行验证;它只会根据自己的验证逻辑接受或拒绝请求。
REST并不是一个包罗万象的范例,它只描述了构建客户端 - 服务器通信的方式。
答案 1 :(得分:12)
我们也遇到了同样的问题。我们让客户端推迟到服务器进行验证的原因是为了防止出现不匹配的规则。在对资源执行操作之前,服务器需要验证所有内容。对这些规则进行两次编码没有任何意义,并且有可能使它们不同步。因此,我们提出了一种似乎与REST一致的策略,同时允许我们要求服务器执行验证。
我们的第一步是实现可以从元数据服务(GET /metadata/user
)请求的元数据对象。然后,此元数据对象用于告知客户端如何进行基本的客户端验证(必需,类型,长度等)。我们从数据库中生成大部分内容。
第二部分包括添加一个名为分析的新资源。例如,如果我们有服务:
GET /users/100
我们将创建一个名为:
的新资源POST /users/100/analysis
分析资源不仅包含发生的任何验证错误,还包含可能需要的相关统计信息。我们争论的问题之一是用于分析资源的动词。我们得出结论,它应该是一个POST,因为在请求时正在创建分析。但是,GET也有很强的论据。
我希望这对试图解决同一问题的其他人有所帮助。任何有关此设计的反馈都表示赞赏。
答案 2 :(得分:11)
您将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>
答案 3 :(得分:0)
在REST API中进行验证是很重要的。无论如何,您需要进行验证,并且不要在客户端使用它。在我的情况下,我只是在API中有一个约定,一个特殊的error_id表示验证错误,而在error_details中,每个feild都有一个错误消息数组,在这个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小时才能在商店发布。
PUT或POST的响应用于显示每个字段的错误消息。这是来自使用React的Web应用程序的相同调用:
这样所有REST API响应代码(如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"
}
}
&#13;
您可以做出可能的修改。 Maby在没有error_id的情况下使用它。如果tehre是error_details,只需循环它们,如果找到与字段同名的键,则将其值作为错误文本放入同一字段。
答案 4 :(得分:0)
一个非常常见的情况是用户或个人资料注册表单的用户名和电子邮件应该是唯一的。通常在文本框模糊时会显示一条错误消息,让用户知道用户名已经存在或者他们输入的电子邮件已经与另一个帐户相关联。其他答案中提到了很多选项,但我不喜欢需要查找 404 的想法,这意味着用户名不存在,因此它是有效的,等待提交以验证整个对象,并返回元数据进行验证无助于检查唯一性。
Imo,应该有一个 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 中进行验证。