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


71

我通常是RESTful API设计的狂热者,但是我不确定如何将REST原理应用于验证API。

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

在这种情况下,有哪些资源?应该使用哪些HTTP状态代码和/或标题?

首先,我GET /profile/validate将查询字符串参数作为参数并返回,204或者返回400有效值或无效值。但validate显然是动词而不是名词。

Answers:


51

您所描述的事物的类型在语义上肯定更像RPC样式,但这并不意味着您无法以RESTful方式实现目标。

没有VALIDATEHTTP动词,因此围绕该结构构建整个API可以得到多少价值?您的故事的重点是为用户提供确定给定用户名是否可用的能力-在我看来,这听起来像是简单的资源检索检查 GET: /profile/username/...--如果结果为404,则该名称可用。

这突出显示的是客户端验证就是客户端验证。UI问题是要确保在将数据发送到服务器之前在客户端上对其进行验证。RESTful服务不会说明客户端是否已执行验证;它只会根据自己的验证逻辑接受或拒绝请求。

REST并不是一个包罗万象的范例,它仅描述了一种构造客户端-服务器通信的方式。


11
您肯定是对的,验证也必须在实际的“更新”调用中进行,但是API中肯定有向客户端公开“验证”功能的值,这样每个客户端都不必这样做(图并重新实现其自己的客户端验证逻辑。同样要澄清的是,验证并不总是像可用性那么简单,例如,可能存在语法规则。但是是的,也许是400 / etc。在这些情况下可以使用。
Aseem Kishore 2012年

没有什么可以阻止API公开您所描述的验证功能的,但是它并不是真正的RESTful-更多的是RPC。我认为您在这里所获得的实际上是一种描述验证规则的资源-换句话说。在实践中,每个客户端很可能最终都需要实施验证逻辑,但是可以通过描述另一个资源的资源来方便地实现这一点
Josh E

1
我们确实确实获得了描述规则的验证“资源”。谢谢!
Aseem Kishore

1
客户端验证和服务器端验证似乎在这里混在一起。客户端验证发送到服务器的数据的方式和方式不必与服务器验证的方式和方式相匹配。例如,服务器可以选择对客户端无法执行的元数据或交叉检查值进行更深入的验证。我同意@JoshE的观点,您应该对资源进行必要的验证,而不是提供一个“验证”资源,我认为这会错误地融合客户端和服务器端的验证。
尼克·瓦茨

19

我们也遇到了同样的问题。我们之所以要让客户端推迟到服务器进行验证,是为了防止规则不匹配。服务器需要先验证所有内容,然后才能对资源进行操作。对这些规则进行两次编码并没有使它们失去同步的潜力是没有意义的。因此,我们提出了一种策略,该策略似乎与REST的思想保持一致,同时允许我们要求服务器执行验证。

我们的第一步是实现可从元数据服务(GET /metadata/user)请求的元数据对象。然后,该元数据对象用于告诉客户端如何进行基本客户端验证(要求,类型,长度等)。我们从数据库中生成其中的大多数。

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

GET /users/100

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

POST /users/100/analysis

分析资源不仅包含发生的任何验证错误,还包含必要时可能相关的统计信息。我们辩论的问题之一是将哪个动词用作分析资源。我们的结论是,这应该是POST,因为在请求时正在创建分析。但是,也有很多关于GET的论点。

我希望这对尝试解决同一问题的其他人有所帮助。感谢对此设计的任何反馈。


4
我认为GET不是正确的动词,因为GET -Requests不应有主体。所以我更喜欢POST,“分析”的想法很棒,并且对我有所帮助,因为我们还在服务器上提供了一个验证查询。
Kirsten

但是,是否analysis违反资源名称为anoun而不是a的规则verb
萨钦

1
我认为这不会破坏资源规则,因为分析是分析某些事物的结果(名词)。
莱斯利·汉克斯

10

您将REST与资源导向相混淆,REST中没有任何内容表明您不能在URL中使用动词。在URL设计方面,我通常选择最能自我描述的内容,而Wheather是名词或动词。

关于您的服务,我要做的是使用与更新相同的资源,但带有testquerystring参数,因此当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>

1
我喜欢提供与“ WhatIf”标志等效的语义的想法
Josh E

16
我不同意第一句话。在REST中,URI应该标识资源(或资源集合)。对于HTTP方法,动词不能是资源,动词只能是动作。参见例如HTTP规范:w3.org/Protocols/rfc2616/rfc2616-sec9.html
罗伯特·罗伯特(Robert)

您可能要使用标题。例如,HTTP用于类似目的的“ if-Match”头。请参阅RFC 7232第3.1节tools.ietf.org/html/rfc7232#section-3.1
Kiril,

@Robert Link关系和媒体类型用于描述资源。URI是不透明的标识符。
Max Toro

-2

在REST API中进行验证非常好。无论如何,您都需要进行验证,并且不要在客户端使用它。就我而言,我只是在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小时才能在商店上发布。

这是在移动应用程序中的样子: 在此处输入图片说明

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"
  }
}

您可以进行可能的修改。Maby使用它时没有error_id。如果是error_details,则将它们循环,如果您找到一个与字段名称相同的键,请将其值作为错误文本放在同一字段中。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.