新(?)尝试构建RESTful基本URL

时间:2011-08-19 13:48:37

标签: ruby-on-rails api http rest

我们都喜欢REST,特别是在开发API时。在过去几年这样做我总是偶然发现同样的问题:嵌套资源。看来我们生活在规模的两个边缘。让我举一个例子。

/galaxies/8/solarsystems/5/planets/1/continents/4/countries.json

NEATO。这样的案例似乎无处不在,无论它们形成什么样的形状。现在,我希望能够获取太阳系中的所有国家,同时能够获取如上所示的深度范围内的国家。

我觉得这里有两个选择。第一个,我展平了我的嵌套结构并引入了许多GET参数(需要我的API用户详细记录和理解),如下所示:

/countries.json?galaxy=8&solarsystem=5&planet=1&continent=4

我可以像这样平整我的所有资源,并为每个资源赢得一个唯一的端点基础URL。好点......每个资源的唯一端点!

但价格是多少?感觉不自然的东西是不可发现的,并且不像我资源下面的树形结构。结论:错误的想法,但很好地实践。

另一方面,我可以尝试摆脱尽可能多的额外GET参数,创建像这样的端点:

/galaxies/8/solarsystems/5/countries.json

但我也需要:

/galaxies/8/solarsystems/5/planets/1/continents/4/countries.json

这似乎是规模的另一面。最少数量的额外GET参数,更自然,但仍然不是我期望的API用户。

我去年使用的大多数API遵循一种或另一种范式。似乎至少有一颗子弹要咬人。那么为什么不做以下事情:

如果有自然嵌套的资源,请让它们完全按照我们希望它们嵌套的方式嵌套。当我们保持这样的时候,我们首先得到的是每个资源的唯一终点:

/galaxies.json
/galaxies/8/solarsystems.json
/galaxies/8/solarsystems/5/planets.json
/galaxies/8/solarsystems/5/planets/1/continents.json
/galaxies/8/solarsystems/5/planets/1/continents/4/countries.json

好的,但是如何解决最初的问题,我想要获取太阳系中的所有国家,同时仍然能够获取完全在星系,太阳系,行星和大陆范围内的国家?这对我来说很自然:

/galaxies/8/solarsystems/5/planets/0/continents/0/countries.json # give me all countries in the solarsystem 5
/galaxies/8/solarsystems/0/planets/0/continents/0/countries.json # give me all countries in the galaxy 8

......依此类推,等等。现在你可能会争辩说“好吧,但那里的零点......”你是对的。看起来不太好看。那么为什么不将两个上限调用更改为:

/galaxies/8/solarsystems/5/planets/all/continents/all/countries.json # give me all countries in the solarsystem 5
/galaxies/8/solarsystems/all/planets/all/continents/all/countries.json # give me all countries in the galaxy 8

整洁呃?那么我们该怎样做?没有额外的GET参数和每个资源端点的稳定基本URL。价钱多少?是的,至少有更长的网址,特别是在使用像curl这样的工具手动测试时。

我想知道这不仅可以提高API的可维护性,还可以提高API的易用性。如果是这样,为什么没有人采取这样的方法。我无法想象成为第一个有这个想法的人。所以必须有一个有效的反驳论据反对这样的方法。我没有看到任何。你呢?

我真的很想听听你的观点和论据支持或反对这样的方法。也许有改进的想法...很高兴收到你的来信。在我看来,这可能会导致更好的结构化API,所以希望有人会阅读并回复。

的问候。 扬

2 个答案:

答案 0 :(得分:1)

这完全取决于数据的呈现方式。用户是否真的需要了解星系#才能找到特定的国家/地区?如果是这样他们你的建议是有道理的。但是,在我看来,你所提议的,虽然结构良好,并且表现良好,但不允许客户搜索子元素,除非父母是已知数量。

在你的例子中,如果我有一个特定的大陆id,我需要知道行星,太阳系和星系。为了找到特定的大陆,我需要为每个可能的父母获得全部,直到我找到该大陆。

如果罚款,以这种方式呈现结构化数据。当你只有一块数据时使用这种结构可能有点麻烦。这一切都取决于你想要完成的事情。

答案 1 :(得分:0)

嵌套资源网址通常很糟糕。我通常采用的方法是使用唯一ID。

设计您的数据库,使其只有一个ID为4的大陆。然后,您需要的只是简单的/galaxies/8/solarsystems/5/planets/1/continents/4/countries.json,而不是可怕的/continents/4/countries.json。清晰,充足,令人难忘。

Rails中的:shallow路由选项会自动执行此操作。

对于“太阳系中的所有国家”,我使用/solar_systems/5/countries.json - 也就是说,不要试图将其置于通用URL方案中。 (并注意下划线。)