每个网络应用程序 - 每个网站 - 都是一项服务。 (...)使网站易于使用的网站功能也使网络服务API易于程序员使用。
Richardson和Ruby,“RESTFul Web Services”
正如我所预料的那样,同时也是Web服务的Web站点提供了其资源的多种表示,具体取决于用户代理请求的内容。可以这么说的API就是网站本身,不是单独提供的。
对于许多流行的“REST API”来说,情况并非如此。例如,Twitter的API位于http://api.twitter.com/1/,URI中的“1”是API本身的版本。 Socialcast还在https://demo.socialcast.com/api/提供REST API,第三级名称是它所处理的网络的名称。
这对我来说似乎不对。如果我的博客位于http://www.example.com/blog,我就不需要在其他位置提供API,仅为机器人提供JSON服务。我不应该使用http://www.example.com/blog/posts/和http://api.example.com/blog/posts这两个不同的URI,而应该只使用前者和多个表示形式,其中application/json
用于我希望提供给用户的JSON API。
示例1 :浏览器询问我博客上的帖子;
请求:
curl -i \
-H "Accept: text/html" \
-X GET \
http://www.example.org/blog/posts/
响应:
200 OK
Content-Type: text/html; charset=utf-8
<html><body><h1>Posts</h1><ol><li><h2>My first post ...
示例2 :相同的URI,但这次机器人发出请求;
请求:
curl -i \
-H "Accept: application/json" \
-X GET \
http://www.example.org/blog/posts/
响应:
200 OK
Content-Type: text/html; charset=utf-8
{
"posts": [
{
"id": 1,
"title": "My first post" ...
API的版本号应该在请求标题的“Accept”字段中进行编码,最重要的是避免像Twitter那样强烈输入URI(“statuses / show.json?id = 210462857140252672”或“status / show / 210462857140252672.json“)。
通过采用统一的方法我可能会失去一些灵活性(但是,不应该Cool URIs never change?),但我认为坚持REST(或者至少我对它的解释)会提供更多的好处。
哪种方法更正确:将API和网站分开,还是将它们统一起来?
答案 0 :(得分:7)
这里没有对错。当您的API开发受特定客户端要求驱动时,REST和RFC过于紧密可能会很困难。
实际上,与API客户端相比,人类用户具有不同的行为模式,因此需要不同的处理方式。最生动的区别在于,许多API都是数据密集型,专为批处理操作和数据转储而设计,而人类用户的应用程序则更具“反应性”,并且通常按要求逐步执行操作。因此,在许多项目中,API URL设计优化,以避免在多个网络往返和重复存储调用上浪费客户端和服务器资源。
在幕后,API实现通常与核心应用程序具有不同的设计,针对API提供的操作进行了优化。例如,API实现可以使用单独的缓存策略。现在,如果您拆分代码,则可能需要创建仅处理API调用的主机群集。这就是将API放在另一个域上变得有利于负载管理:单独的域允许在高负载站点上实现更简单的负载平衡。相比之下,当您在同一域名上使用/ api URL前缀(但具有单独的集群)时,您需要一个智能(L7感知)负载均衡器来完成在API和Web前端集群之间拆分请求流的工作,但是这种负载平衡器更贵。
因此,可能有非常好的技术原因会让Twitter之类的人将API分开,但对其他实现的引用可能不适用于您的项目。如果您处于设计的早期阶段,您可能希望从同一域上的统一URL方案开始,但最终您可能会发现有很好的实际用例可以让您更改方法,然后......重构。
P.S。关于版本控制的讨论很长 - Best practices for API versioning?
P.S.S。我发现强类型的URL有助于快速调试。您可以使用.json将URL放入浏览器中,并快速获取结果,而无需切换到命令行。但同意你“接受”标题是首选方法
P.S.S.S。 API的SEO?我可以看到一个好的URL设计如何有益,但对于搜索引擎,如果您的服务在相同的路径/域名上提供多种输出格式,它可能无关紧要。在一天结束时,搜索引擎是为人类用户构建的,而人类用户不使用XML和JSON。
答案 1 :(得分:2)
Web和RESTful API可能以不同的方式运行。
理论上,如果需要返回HTML页面或仅返回数据(JSON,XML ...),http://mysite.com/blog/1
之类的请求会如何区分?我会投票使用Accept
http标头:
Accept: text/html <-- Web browsers
Accept: application/json <-- Applications/Relying parties consuming data or performing actions
为什么Twitter,Facebook或其他网站不会混合Web浏览器和依赖方?老实说,我认为这是一个武断的决定。
也许我可以提供一个可能的原因:Web浏览器/搜索引擎机器人URL应该是 friendly-URLs ,因为这些在SEO上工作得更好。出于这个原因,也许SEO准备好的URL在REST方面不是非常语义,但它们适用于搜索引擎甚至是人类用户!
最后:哪个更好(这是我的意见)?
答案 2 :(得分:1)
我不同意另一个答案,即这个决定应该与SEO有关,或者URL是多么“友好”(机器人也是由人写的!)。但我的直觉告诉我,更好的搜索引擎优化结果将来自统一 URI,因为这也会在您的API URI将从世界狂野网络链接到的(不太可能的)事件中统一pagerank。
应该依赖的决定是您的服务器和客户端能够做什么。如果他们可以设置Accept请求标头,并且您的服务器足够聪明,可以进行透明内容协商,那么请务必统一URI。这就是我所做的(我唯一的JSON客户端就是我自己,发出从我的网络应用程序的其他HTML部分提供的AJAX请求,我在那里控制Accept标头)。
如果客户端无法设置请求标头,例如想要获取json响应的Web用户,则最终会使用默认值(可能是text / html)。因此,您可能希望允许在唯一URI(/foo.txt,/ foo.rtf)下进行非协商响应。通常,这是通过将格式附加到由点分隔的URI来完成的,就好像它是文件扩展名(但通常不是,mod_rewrite执行杂耍),以便需要文件扩展名的平台上的旧客户端可以保存文件有意义的。
我网站上的大多数网页都是这样的:
/cars?colour=black
=&gt; SELECT * FROM cars WHERE colour='black'
)text/html
。<HEAD>
和<NAV>
(考虑参数:<h1>Black Cars</h1>
)Link
标头,HTML <LINK>
元素流,HAL的_links
键,XLink元素流,HTML { {1}}元素(包含<TABLE>
个元素的单元格)或CSV文件。 SQL查询可能返回0行,在这种情况下,如果正在使用该输出,则会写入用户友好的消息而不是HTML表。<A>
这个基本大纲处理我的Web应用程序中大约30个不同的资源集合,尽管每个资源集合都有一组请求URI可以调用的不同选项,因此每个资源集合的开头在参数验证方面都有所不同。
所以,现在我已经解释了所有这些,你可以看到在一个地方处理每个资源的所有细节可能是有用的,以及通过公共库函数处理格式X或格式Y的泛型。这是一个实现细节,可以减轻我的生活,并帮助我坚持不要重复自己的格言。
答案 3 :(得分:0)
我绝对不同意网站==网络服务方法。
简而言之,该网站应被视为客户端,只是客户端,它使用Web服务并以适当的形式呈现数据供Web使用。就像移动应用程序是一个客户端,只是一个客户端,使用相同的Web服务并以适当的形式呈现数据以供移动使用。
网络服务是服务提供商。所有其他人都只是客户;网站,Android应用程序,iPhone应用程序等......