我正在努力决定如何设计restful url。我完全赞成使用带有名词而不是动词的url的restful方法,我不知道如何做到这一点。

我们正在创建一个服务来实现一个金融计算器。计算器接受一堆参数,我们将通过CSV文件上传这些参数。用例包括:

上传新参数 获取最新参数 获取给定业务日期的参数 激活一组参数 验证一组参数

我收集的restful方法将有以下类型的url:

/parameters
/parameters/12-23-2009

你可以通过以下方法实现前三个用例:

在POST请求中包含参数文件 第一个URL的GET 第二个URL的GET

但是在没有动词的情况下如何完成第4和第5个用例呢?你不需要这样的url吗:

/parameters/ID/activate
/parameters/ID/validate

??


当前回答

好的URI设计的一般原则:

Don't use query parameters to alter state Don't use mixed-case paths if you can help it; lowercase is best Don't use implementation-specific extensions in your URIs (.php, .py, .pl, etc.) Don't fall into RPC with your URIs Do limit your URI space as much as possible Do keep path segments short Do prefer either /resource or /resource/; create 301 redirects from the one you don't use Do use query parameters for sub-selection of a resource; i.e. pagination, search queries Do move stuff out of the URI that should be in an HTTP header or a body

(注意:我没有说“rest式URI设计”;uri在REST中本质上是不透明的。)

HTTP方法选择的一般原则:

Don't ever use GET to alter state; this is a great way to have the Googlebot ruin your day Don't use PUT unless you are updating an entire resource Don't use PUT unless you can also legitimately do a GET on the same URI Don't use POST to retrieve information that is long-lived or that might be reasonable to cache Don't perform an operation that is not idempotent with PUT Do use GET for as much as possible Do use POST in preference to PUT when in doubt Do use POST whenever you have to do something that feels RPC-like Do use PUT for classes of resources that are larger or hierarchical Do use DELETE in preference to POST to remove resources Do use GET for things like calculations, unless your input is large, in which case use POST

使用HTTP设计web服务的一般原则:

Don't put metadata in the body of a response that should be in a header Don't put metadata in a separate resource unless including it would create significant overhead Do use the appropriate status code 201 Created after creating a resource; resource must exist at the time the response is sent 202 Accepted after performing an operation successfully or creating a resource asynchronously 400 Bad Request when someone does an operation on data that's clearly bogus; for your application this could be a validation error; generally reserve 500 for uncaught exceptions 401 Unauthorized when someone accesses your API either without supplying a necessary Authorization header or when the credentials within the Authorization are invalid; don't use this response code if you aren't expecting credentials via an Authorization header. 403 Forbidden when someone accesses your API in a way that might be malicious or if they aren't authorized 405 Method Not Allowed when someone uses POST when they should have used PUT, etc 413 Request Entity Too Large when someone attempts to send you an unacceptably large file 418 I'm a teapot when attempting to brew coffee with a teapot Do use caching headers whenever you can ETag headers are good when you can easily reduce a resource to a hash value Last-Modified should indicate to you that keeping around a timestamp of when resources are updated is a good idea Cache-Control and Expires should be given sensible values Do everything you can to honor caching headers in a request (If-None-Modified, If-Modified-Since) Do use redirects when they make sense, but these should be rare for a web service

关于你的具体问题,第4和第5点应该用POST。这些操作属于上面的“类rpc”准则。对于#5,记住POST不一定要使用Content-Type: application/x-www-form-urlencoded。这也可以是一个JSON或CSV有效负载。

其他回答

也许是这样的:

PUT /parameters/activation HTTP/1.1
Content-Type: application/json; encoding=UTF-8
Content-Length: 18

{ "active": true }

激活和验证需求是试图更改资源状态的情况。将一个订单“完成”或其他一些请求“提交”是没有区别的。有许多方法可以对这种状态变化建模,但我发现最有效的一种方法是为相同状态的资源创建集合资源,然后在集合之间移动资源以影响状态。

例如:创建一些资源,例如:

/ActiveParameters
/ValidatedParameters

如果要使一组参数处于活动状态,则将该集添加到ActiveParameters集合。您可以将参数集作为实体体传递,也可以将url作为查询参数传递,如下所示:

POST /ActiveParameters?parameter=/Parameters/{Id}

同样的事情也可以用/ValidatedParameters完成。如果参数无效,则服务器可以向请求返回“Bad Request”,将参数添加到已验证参数的集合中。

编辑:URI确实会阻止GET请求保持幂等性。


然而,对于验证,使用HTTP状态代码来通知请求的有效性(创建一个新的或修改一个现有的“参数”)将适合Restful模型。

如果提交的数据无效,并且在重新提交请求之前必须修改请求,则返回400坏请求状态码(HTTP/1.1状态码)。

不过,这依赖于在提交时进行验证,而不是像在用例中那样推迟。其他答案都有适合该场景的解决方案。

我建议使用以下Meta资源和方法。

使参数激活和/或验证它们:

> PUT /parameters/<id>/meta HTTP/1.1
> Host: example.com
> Content-Type: application/json
> Connection: close
>
> {'active': true, 'require-valid': true}
>
< HTTP/1.1 200 OK
< Connection: close
<

检查参数是否激活且有效:

> GET /parameters/<id>/meta HTTP/1.1
> Host: example.com
> Connection: close
>
< HTTP/1.1 200 OK
< Content-Type: application/json
< Connection: close
<
< {
<     'active': true,
<     'require-valid': true,
<     'valid': {'status': false, 'reason': '...'}
< }
<

url的设计与应用程序是否是RESTful无关。因此,“RESTful url”这个短语是毫无意义的。

我认为你应该多读一些关于REST到底是什么的书。REST将url视为不透明的,因此不知道其中有什么,是否有动词或名词或其他什么。您可能仍然希望设计url,但这是关于UI,而不是REST。

也就是说,让我们来回答您的问题:最后两种情况不是RESTful的,不适合任何类型的RESTful方案。这些就是所谓的RPC。如果认真对待REST,就必须重新思考应用程序如何从头开始工作。要么放弃REST,把你的应用程序作为RPC应用程序。

嗯,也许不是。

这里的想法是,你必须把所有东西都当作资源,所以一旦一组参数有了一个URL,你可以引用它,你只需要添加:

GET [parametersurl]/validationresults

POST [paramatersurl]
body: {command:"activate"}

但是,那个激活的东西是RPC,不是REST。