URI命名层次结构建议

时间:2010-11-25 16:53:30

标签: rest uri naming hierarchy

我正在尝试构建一个基于Rest的服务,该服务具有广泛的体育数据数据(结果/固定装置/球队/球员/联赛等)和相关统计数据。

现在,我想出了一个合适的URI层次结构。例如,我可以实现......

1)i)版本/体育/联赛/赛季/ 实体

1)ii)版本/ 实体 / sports / league / season

1)iii)版本/体育/ 实体 /联盟/季节

一个例子让事情变得更加清晰(希望如此)......

回答所有在2010/2011赛季都在英超联赛中踢球的足球运动员...

2)i)1.1 / football / premier_league / 2010_2011 / 球员

2)ii)a)1.1 / 球员 / football // premier_league / 2010_2011

但并非所有运动(例如赛马 - 赛马,骑师,F1等)都有球员,所以球员应该参加这项运动吗?

2)ii)b)1.1 / 匹马 / horse_racing / gold_cup / 2010

2)iii)a)1.1 /足球/ 球员 / premier_league / 2010_2011

2)iii)b)1.1 / horse_racing / horse / gold_cup / 2010

以下更多示例URI ...

1.1 /的玩家 /足球/ premier_league / 2010_2011 /支/ {ID}
回归球队的球员??

1.1 /的玩家 /足球/ premier_league 返回英超联赛的球员?

1.1 /的结果 /足球/ premier_league / 2010_2011 /支/ {ID} 返回团队赛季的结果?

我也设想像......这样的查询。

1.1 /足球/ premier_league / 2010_2011 /的十一月 /支/ {ID} /结果

将月份作为缩小结果集的参数。

如果服务必须包括非体育实体,说政治选举......就没有球员......

1.1 /选举/ 2012 /方/ {ID} /的结果
返回政党的结果

1.1 /选举/ 2012 /方/ {ID} /的候选 返回与该党相关的候选人

或 1.1 /的结果 /选举/ 2012 /方/ {ID} 返回政党的结果

1.1 /的候选 /选举/ 2012 /方/ {ID} 返回与该党相关的候选人

关于哪种层次结构更好的建议?我试过搜索这个网站和谷歌,但我发现的例子只涉及琐碎的案例。我想我赞成例2-iii。

提前致谢。

1 个答案:

答案 0 :(得分:3)

我的建议是为您的实体创建包含所需信息量最少的标识符。 e.g。

/sport/{unqiueId}
/player/{unqiueId}
/horse/{unqiueId}
/team/{unqiueId}
/league/{unqiueId}
/season/{unqiueId}
/result/{unqiueId}

请注意,我从网址中删除了版本,因为我坚定地认为版本不属于网址。

可以通过将链接嵌入到响应中的实体来处理一对一关系:例如

GET /player/234
=>
<Player Name="Kenny Dalglish">
   <Link rel="team" href="/team/732"/>
</Player>

可以类似地处理一对多关系,但它需要创建实体资源的子资源。

GET /team/732
=>
<team Name="Liverpool FC">
   <Link rel="players" href="/team/732/players"/>
</Player>

通常你会发现这种模式很有用的所有场景:

/league/{unqiueId}/teams
/league/{unqiueId}/players
/season/{unqiueId}/teams
/league/{unqiueId}/seasons
/player/{unqiueId}/teams
/sport/{unqiueId}/teams
/sport/{unqiueId}/leagues
/sport/{unqiueId}/seasons

对于仅包含数据子集但是常见查询的表示,可以使用查询字符串轻松创建它们并将其嵌入到结果中:

GET /league/891
=>
<league Name="Premiership">
   <link rel="leaderboard" href="/league/891/teams?startposition=1&endposition=10"/>
   <link rel="currentseason" href="/season/972"/>
   <link rel="lastseason" href="/season/842"/>
   <link rel="sport" href="/sport/1"/>
   <link rel="teams" href="/teams?league=891/>
</league>

这种类型的“api”的一个有趣特征是,客户端应用程序采用不同的方法,而不是在客户端应用程序中构建关于如何构建url结构以发出请求的整个规则。客户端需要知道起始URL和rel属性值的含义。从那里客户端可以导航以获得它想要的东西。 e.g。

而不是客户端根据服务器层次结构的硬编码知识构建请求,而不是:

GET /Sport/Football/League/Premiership/Season/2011/Teams

而是导航它的结果如下:

GET /
=>
<SportData>
  <Link rel="sport football" href="/sport/1"/>  <!-- Client finds this link -->
  <Link rel="sport horseracing" href="/sport/2"/>
  ...
</SportData>

GET /sport/1
=>
<Sport Name="Football">
  <Link rel="league premiership" href="/league/891"/>  <!-- Client finds this link -->
  ...
</Sport>

GET /league/891
=>
<League Name="Premiership">
  <Link rel="season 2011" href="/season/2334"/>  <!-- Client finds this link -->
  ...
</League>


GET /season/2334
=>
<Season Name="2011">
  <Link rel="teams" href="/season/2334/teams"/>  <!-- Client finds this link -->
  ...
</Season>

我意识到这似乎比第一个选项更多的工作,但是,它并没有看起来那么糟糕。使用缓存和书签可以大大减少往返次数。主要好处是您可以轻松更改服务公开的资源,并在资源之间引入新的关系,而不会对客户端产生任何影响。

理想情况下,在基于REST的系统中,客户端和服务器之间的唯一耦合是根URL和来回发送的媒体类型。客户端需要对服务器的URL空间一无所知。