【问题标题】:URI naming hierarchy adviceURI 命名层次结构建议
【发布时间】:2010-11-25 16:53:29
【问题描述】:

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

目前,想出一个合适的 URI 层次结构让我绕圈子。例如我可以实现...

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

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

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

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

进行查询,返回所有在 2010/2011 赛季参加英超联赛的足球运动员...

2) i) 1.1/football/premier_league/2010_2011/players

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/football/players/premier_league/2010_2011

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

下面有更多示例 URI...

1.1/players/football/premier_league/2010_2011/teams/{id}
赛季回归球队?

1.1/球员/football/premier_league 回归英超联赛的球员?

1.1/结果/football/premier_league/2010_2011/teams/{id} 返回团队赛季的结果?

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

1.1/football/premier_league/2010_2011/11 月/teams/{id}/results

以月份作为参数来缩小结果集。

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

1.1/election/2012/parties/{id}/结果
返回政党的结果

1.1/election/2012/parties/{id}/候选人 返回与该党相关的候选人

或 1.1/结果/election/2012/parties/{id} 返回政党的结果

1.1/候选人/election/2012/parties/{id} 返回与该党相关的候选人

关于哪个层次结构更好的建议?我试过搜索这个网站和谷歌,但我发现的例子只涵盖了琐碎的案例。我认为我喜欢示例 2-iii。

提前致谢。

【问题讨论】:

    标签: rest uri naming hierarchy


    【解决方案1】:

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

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

    请注意,我从 URL 中删除了版本,因为我坚信版本不属于 URL。

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

    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 属性值的含义。从那里客户可以导航以获得它想要的东西。例如

    而不是客户端基于服务器层次结构的硬编码知识构建请求,如下所示:

    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 空间。

    【讨论】:

    • Darrel,感谢您的详细回复,非常有帮助 - 关于版本号的点,我会废弃它。
    • Darrel,你能详细说明为什么版本号不应该在 URI 中吗? (那么它应该在哪里?)
    • @Josh Here stackoverflow.com/questions/972226/how-to-version-rest-uris/… 是我对这个问题的回答。
    • 那么,为“rel”使用自定义值是公认的做法,还是为了获得更丰富的语义而妥协?
    • @Eugen 是的,使用 rels 是向现有媒体类型添加语义的公认方式。您可以使用此处定义的标准iana.org/assignments/link-relations/link-relations.xml,也可以根据 RFC 5988 定义自定义的。我在上面的示例中作弊,因为自定义 rel 应该是一个 URI。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-20
    相关资源
    最近更新 更多