在一个小小的项目上工作,我现在有机会设计我自己的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
和z
的任何值。
我非常喜欢方法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 references specific lines or ranges of lines的方式之后,我想到将范围定义为不同的集合,例如:
/series/:id/:year/:month
(与之前相同)/series/:id/:year/:frommonth-:tomonth
(获取特定范围)/series/:id/:year/-:tomonth
(从一年开始到tomonth
)/series/:id/:year/:frommonth-
(从frommonth
到今年年底的所有内容)现在,问题: