在做一个小项目时,我现在有机会设计自己的 API。如果这不是一项商业活动,那么这是我了解更多关于 REST、资源、集合和 URI 的机会。
我的服务记录按时间序列组织的数据点,并将很快提供一个 API 来轻松查询特定系列的数据点范围。数据点是不可变的,因此应该是非常好的缓存候选者。时间序列只能在有限的时间窗口内更新,之后它们只能存档和读取(使它们也“可缓存”)。
我一直在研究一些提供同类服务的公司的API,发现了以下两种模式:
定义路径中的系列和查询中的范围:
/series/:id?from=2017-01-26&to=2017-01-27
这几乎是大多数服务所使用的。我将其理解为系列是资源/集合,然后被切片到特定范围。从消费者的角度来看,这似乎很容易使用,但从数据的角度来看,查询中的日期是某种组织或层次结构的一部分,在这种情况下应该是路径的一部分。
定义路径中的系列和坐标:
/series/:x/:y/:z
我没有找到时间序列的例子,但它是用于基于瓦片的地图服务的那种结构。
x
对我来说,这意味着 和 的每个组合y
都是z
一个不同的集合,在某些情况下可能包含或不包含相同的资源。它还直接映射到某个层次结构,/series/:x
包含具有特定值的所有系列x
和任何值y
andz
。
我真的很喜欢方法 2 的想法。我从以下内容开始:
/series/:id
(来自特定系列的所有数据点)/series/:id/:year
(来自特定系列的所有数据点和year
)/series/:id/:year/:month
/series/:id/:year/:month/:day
...
这对于查询预定义范围非常有效,例如“2016 年的所有数据点”或“2016 年 1 月的所有数据点”。尝试查询“2016 年 1 月至 2016 年 3 月的所有数据点”等任意范围时会出现问题。
我的第一个试验是简单地将开始和结束添加到路径中:
/series/:id/:year
(特定年份的所有数据点)/series/:id/:fromyear/:toyear
fromyear
(和之间的所有数据点toyear
)
但:
它变得非常长,非常快。示例:
/series/:id/:fromyear/:frommonth/:fromday/:toyear/:tomonth/:today
并且可能非常麻烦,具体取决于所选的结构/series/:id/:fromyear/:toyear/:frommonth/:tomonth/:fromday/:today
从层次结构或结构的角度来看,它没有任何意义。在
/series/1/2014/2016
, 2016 不是 2014 的子集,此集合实际上将返回 2014、2015 和 2016 的数据点。在服务器端处理起来很棘手。
/series/1/2016/01/02
应该返回 1 月 2 日或整个 1 月到 2 月范围内的所有数据点?
在注意到Github 在其片段中引用特定行或行范围的方式后,我尝试将范围定义为不同的集合,例如:
/series/:id/:year/:month
(和以前一样)/series/:id/:year/:frommonth-:tomonth
(获得特定范围)/series/:id/:year/-:tomonth
(得到从年初到的所有东西tomonth
)/series/:id/:year/:frommonth-
frommonth
(从年底到年底得到所有东西)
现在,问题:
- 我的解决方案是否破坏了任何 REST 或语义 URL 规则/概念/想法?
- 与在查询中使用范围相比,它是否改善了缓存?
- 它会损害消费者的可用性吗?
- 它是不自然的还是违反了某些前端框架的不成文规则?