我们正在推出一个新的REST API,我想要一些关于我们应该如何格式化输入参数的最佳实践的社区意见:
现在,我们的API非常以JSON为中心(只返回JSON)。是否希望/需要返回XML是另一个问题。
由于我们的API输出是以JSON为中心的,我们一直在走一条路径,我们的输入有点以JSON为中心,我一直在想,这可能对一些人来说很方便,但总的来说很奇怪。
例如,要获得一些产品细节,可以同时提取多个产品,我们目前有:
http://our.api.com/Product?id=["101404","7267261"]
我们是否可以将其简化为:
http://our.api.com/Product?id=101404,7267261
或者有JSON输入方便吗?更痛苦?
我们可能想要接受这两种风格,但是这种灵活性实际上会导致更多的混乱和头痛(可维护性、文档等)吗?
更复杂的情况是当我们想要提供更复杂的输入时。例如,如果我们想在搜索中允许多个过滤器:
http://our.api.com/Search?term=pumas&filters={"productType":["Clothing","Bags"],"color":["Black","Red"]}
我们不一定要把过滤器类型(例如productType和color)作为请求名称,就像这样:
http://our.api.com/Search?term=pumas&productType=["Clothing","Bags"]&color=["Black","Red"]
因为我们想把所有的过滤器输入组合在一起。
说到底,这真的重要吗?可能有太多的JSON util,输入类型并不那么重要。
我知道对API进行AJAX调用的JavaScript客户端可能会喜欢JSON输入,以使他们的工作更轻松。
第一:
我认为有两种方法
http://our.api.com/Product/<id>:如果你只想要一条记录
http://our.api.com/Product:如果你想要所有的记录
http://our.api.com/Product/<id1>,<id2>:正如James建议的那样,可以作为一个选项,因为Product标记后面的内容是一个参数
或者我最喜欢的是:
您可以使用RestFul WS的Hypermedia作为应用程序状态的引擎(HATEOAS)属性,并调用http://our.api.com/Product,该调用应该返回http://our.api.com/Product/<id>的等效url,并在此之后调用它们。
第二个
当你必须对url调用进行查询时。我建议再次使用HATEOAS。
1)给http://our.api.com/term/pumas/productType/clothing/color/black打个get电话
2)给http://our.api.com/term/pumas/productType/clothing,bags/color/black,red打个get电话
3)(使用HATEOAS)做一个得到调用' http://our.api.com/term/pumas/productType/ ->接收url所有服装可能的url ->调用那些你想要的(服装和包)->接收可能的颜色url ->调用那些你想要的
后退一步
首先,REST将URI描述为通用唯一ID。太多的人纠结于uri的结构以及哪些uri比其他uri更“rest化”。这个论点就像说给一个人起名叫“Bob”比给他起名叫“Joe”更好一样可笑——这两个名字都能完成“识别一个人”的工作。URI只不过是一个普遍唯一的名称。
因此,在REST的眼中,争论?id=["101404","7267261"]是否比?id=101404,7267261或\Product\101404,7267261更安静,多少有些徒劳。
话虽如此,很多时候,uri的构造方式通常可以作为rest式服务中其他问题的良好指示器。在您的uri和问题中有一些危险信号。
建议
Multiple URIs for the same resource and Content-Location
We may want to accept both styles but does that flexibility actually cause more confusion and head aches (maintainability, documentation, etc.)?
URIs identify resources. Each resource should have one canonical URI. This does not mean that you can't have two URIs point to the same resource but there are well defined ways to go about doing it. If you do decide to use both the JSON and list based formats (or any other format) you need to decide which of these formats is the main canonical URI. All responses to other URIs that point to the same "resource" should include the Content-Location header.
Sticking with the name analogy, having multiple URIs is like having nicknames for people. It is perfectly acceptable and often times quite handy, however if I'm using a nickname I still probably want to know their full name – the "official" way to refer to that person. This way when someone mentions someone by their full name, "Nichloas Telsa", I know they are talking about the same person I refer to as "Nick".
"Search" in your URI
A more complex case is when we want to offer more complex inputs. For example, if we want to allow multiple filters on search...
A general rule of thumb of mine is, if your URI contains a verb, it may be an indication that something is off. URI's identify a resource, however they should not indicate what we're doing to that resource. That's the job of HTTP or in restful terms, our "uniform interface".
To beat the name analogy dead, using a verb in a URI is like changing someone's name when you want to interact with them. If I'm interacting with Bob, Bob's name doesn't become "BobHi" when I want to say Hi to him. Similarly, when we want to "search" Products, our URI structure shouldn't change from "/Product/..." to "/Search/...".
回答你最初的问题
Regarding ["101404","7267261"] vs 101404,7267261: My suggestion here is to avoid the JSON syntax for simplicity's sake (i.e. don't require your users do URL encoding when you don't really have to). It will make your API a tad more usable. Better yet, as others have recommended, go with the standard application/x-www-form-urlencoded format as it will probably be most familiar to your end users (e.g. ?id[]=101404&id[]=7267261). It may not be "pretty", but Pretty URIs does not necessary mean Usable URIs. However, to reiterate my initial point though, ultimately when speaking about REST, it doesn't matter. Don't dwell too heavily on it.
Your complex search URI example can be solved in very much the same way as your product example. I would recommend going the application/x-www-form-urlencoded format again as it is already a standard that many are familiar with. Also, I would recommend merging the two.
你的URI ...
/Search?term=pumas&filters={"productType":["Clothing","Bags"],"color":["Black","Red"]}
你的URI被URI编码后…
/Search?term=pumas&filters=%7B%22productType%22%3A%5B%22Clothing%22%2C%22Bags%22%5D%2C%22color%22%3A%5B%22Black%22%2C%22Red%22%5D%7D
可以转化为……
/Product?term=pumas&productType[]=Clothing&productType[]=Bags&color[]=Black&color[]=Red
除了避免对URL编码的要求并使事情看起来更标准之外,它现在还使API更加同质化了。用户知道,如果他们想检索一个Product或List of Products(两者在RESTful术语中都被视为单个“资源”),他们对/Product/…uri。
我会支持nategood的回答,因为它是完整的,它似乎满足了你的需要。尽管如此,我还是想补充一个关于以这种方式识别多个(1个或更多)资源的评论:
http://our.api.com/Product/101404,7267261
在这样做时,你:
使客户端复杂化
迫使他们将你的响应解释为一个数组,如果我提出以下请求:http://our.api.com/Product/101404,这对我来说是违反直觉的
创建冗余api
用一个API获取所有产品,上面的API获取1个或多个产品。因为出于用户体验的考虑,你不应该向用户显示超过1页的详细信息,我认为超过1个ID是没有用的,纯粹是用来过滤产品的。
这可能不是什么问题,但是您要么必须自己在服务器端通过返回单个实体(通过验证您的响应是否包含一个或多个实体)来处理这个问题,要么让客户端管理它。
例子
我想从《神奇》订购一本书。我确切地知道这是哪本书,当我导航恐怖书籍时,我在列表中看到它:
10000条惊人的线,0个惊人的测试
神奇怪物的回归
让我们复制令人惊叹的代码
结局的惊人开端
在选择第二本书后,我被重定向到一个详细介绍列表中书籍部分的页面:
--------------------------------------------
Book #1
--------------------------------------------
Title: The return of the amazing monster
Summary:
Pages:
Publisher:
--------------------------------------------
还是在一页里只给我这本书的全部细节?
---------------------------------
The return of the amazing monster
---------------------------------
Summary:
Pages:
Publisher:
---------------------------------
我的意见
我建议在获取该资源的详细信息时,当保证惟一性时,在路径变量中使用ID。例如,下面的api提供了获取特定资源详细信息的多种方法(假设产品有唯一的ID,该产品的规范有唯一的名称,并且您可以自顶向下导航):
/products/{id}
/products/{id}/specs/{name}
当您需要多个资源时,我建议从更大的集合中筛选。同样的例子:
/products?ids=
当然,这是我的意见,因为它不是强加的。