我正在尝试构建一个基于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。
提前致谢。
答案 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空间一无所知。