RESTful API - 处理依赖于其他更新的更新
RESTful API - handling updates that depend on other updates
我正在尝试设计一个 RESTful API 来为前端 JS 应用程序提供数据,并在我开始编写它后在将来为本机移动应用程序提供服务。
我对前端开发还很陌生,所以 API 设计对我来说也很陌生。我正在编写一个 table 网球联赛应用程序来开始我的学习,其中一个端点似乎不太适合我读过的推荐 API 结构的任何示例。
我有两个实体,联盟和球员。联盟有一组球员,当输入结果时,如果在比赛开始前获胜者低于失败者,则球员会在联盟中切换 "position"。
标准 REST API 可能具有如下端点以更新联盟中特定球员的详细信息:
(POST/PATCH) - /api/v1/leagues/{league-id}/players/{player-id}
例如/api/v1/leagues/1/玩家/12
这很好,但在我的例子中,当将结果输入网络应用程序时,2 个不同的玩家需要通过 API 更新他们的 "position" 值。理想情况下,我会将此设置为数据库中的唯一字段,因此在任何给定时间,联盟中的每个位置只能有 1 名球员。但是,如果是这种情况,使用上面的 API 端点,我的前端应用程序将需要根据输入的结果计算玩家的新位置,更新玩家 1,然后如果成功更新玩家2(失败回滚)。按照这种结构,位置字段不能是唯一的,因为在玩家 1 更新之后,它们都具有相同的位置值,直到玩家 2 更新。
我能想到的唯一其他解决方案是拥有一些其他适当命名的端点,该端点采用 "result" 对象,在服务器端执行计算玩家新位置的逻辑,并相应地更新,和 returns 一些数据供 UI 重新绑定和更新。
所以我的问题是:您会选择上述两种方法中的哪一种,为什么?
如果您选择后者,您会 return 从 API 调用中为 UI 绑定哪些数据?完整的球员数据联盟?还是只更新了两个播放器?
谢谢
选择在何处计算联赛中的位置是非常主观的 - 我建议在服务器上进行,因为它涉及再次搜索数据库(其他玩家的得分)。
因为你有多个球员,你可能一次更新 2 个球员,最好在请求正文中发送球员的分数和他们的位置,以及 return 计算出的完整联赛信息每个请求的响应,因为这将简化您的客户端代码并确保您获得最新数据。
此建议基于您在联赛中没有大量球员(可能 > 100)的假设。在那种情况下,我建议方法 1 更好。
所以你的 API URL 可以是..
(POST) /api/v1/leagues/{league-id}
而你的请求正文,可以是
"players":[
{"player-id":"101", "newScore":"10"},
{"player-id":"103","newScore":"20"}
]
您的回复可以是生成的联赛中球员的完整列表。
"players":[
{"player-id":"101", "position":"1"},
{"player-id":"102", "position":"2"},
{"player-id":"103","position":"3"}
{"player-id":"104","position":"4"}
{"player-id":"105","position":"5"}
]
我想我看到了两个问题
- 你没有定义足够的资源
- 您将 http 与您的域模型混淆了
尝试这样的事情
PUT /api/v1/matches/{match-id}
{ winner : { id }, loser : { id }, ... }
向 API 发送一条描述游戏结果的消息(POST 可以接受,PUT 更适合幂等性)。
作为此消息到达的副作用,将结果合并到您的域模型中。您的领域模型应包含描述游戏结束时玩家排名如何变化的规则。
当有人想看玩家的排名时...
GET /api/v1/leagues/{league-id}/standings
您将它们发送到 returns 代表您模型中当前排名的资源。
uri 的拼写不是特别重要;我更喜欢 "standings",因为我相信这在您的域中是真实存在的。但是如果你想在没有额外上下文的情况下反映资源的数据结构,你可以使用像
这样的拼写
GET /api/v1/leagues/{league-id}/players?orderBy=position
客户端发送给您的请求正文中的数据表示不是您的域模型中实体的序列化,它是发送给您的域模型的消息的序列化。
我正在尝试设计一个 RESTful API 来为前端 JS 应用程序提供数据,并在我开始编写它后在将来为本机移动应用程序提供服务。
我对前端开发还很陌生,所以 API 设计对我来说也很陌生。我正在编写一个 table 网球联赛应用程序来开始我的学习,其中一个端点似乎不太适合我读过的推荐 API 结构的任何示例。
我有两个实体,联盟和球员。联盟有一组球员,当输入结果时,如果在比赛开始前获胜者低于失败者,则球员会在联盟中切换 "position"。
标准 REST API 可能具有如下端点以更新联盟中特定球员的详细信息:
(POST/PATCH) - /api/v1/leagues/{league-id}/players/{player-id}
例如/api/v1/leagues/1/玩家/12
这很好,但在我的例子中,当将结果输入网络应用程序时,2 个不同的玩家需要通过 API 更新他们的 "position" 值。理想情况下,我会将此设置为数据库中的唯一字段,因此在任何给定时间,联盟中的每个位置只能有 1 名球员。但是,如果是这种情况,使用上面的 API 端点,我的前端应用程序将需要根据输入的结果计算玩家的新位置,更新玩家 1,然后如果成功更新玩家2(失败回滚)。按照这种结构,位置字段不能是唯一的,因为在玩家 1 更新之后,它们都具有相同的位置值,直到玩家 2 更新。
我能想到的唯一其他解决方案是拥有一些其他适当命名的端点,该端点采用 "result" 对象,在服务器端执行计算玩家新位置的逻辑,并相应地更新,和 returns 一些数据供 UI 重新绑定和更新。
所以我的问题是:您会选择上述两种方法中的哪一种,为什么?
如果您选择后者,您会 return 从 API 调用中为 UI 绑定哪些数据?完整的球员数据联盟?还是只更新了两个播放器?
谢谢
选择在何处计算联赛中的位置是非常主观的 - 我建议在服务器上进行,因为它涉及再次搜索数据库(其他玩家的得分)。
因为你有多个球员,你可能一次更新 2 个球员,最好在请求正文中发送球员的分数和他们的位置,以及 return 计算出的完整联赛信息每个请求的响应,因为这将简化您的客户端代码并确保您获得最新数据。
此建议基于您在联赛中没有大量球员(可能 > 100)的假设。在那种情况下,我建议方法 1 更好。
所以你的 API URL 可以是..
(POST) /api/v1/leagues/{league-id}
而你的请求正文,可以是
"players":[ {"player-id":"101", "newScore":"10"}, {"player-id":"103","newScore":"20"} ]
您的回复可以是生成的联赛中球员的完整列表。
"players":[ {"player-id":"101", "position":"1"}, {"player-id":"102", "position":"2"}, {"player-id":"103","position":"3"} {"player-id":"104","position":"4"} {"player-id":"105","position":"5"} ]
我想我看到了两个问题
- 你没有定义足够的资源
- 您将 http 与您的域模型混淆了
尝试这样的事情
PUT /api/v1/matches/{match-id}
{ winner : { id }, loser : { id }, ... }
向 API 发送一条描述游戏结果的消息(POST 可以接受,PUT 更适合幂等性)。
作为此消息到达的副作用,将结果合并到您的域模型中。您的领域模型应包含描述游戏结束时玩家排名如何变化的规则。
当有人想看玩家的排名时...
GET /api/v1/leagues/{league-id}/standings
您将它们发送到 returns 代表您模型中当前排名的资源。
uri 的拼写不是特别重要;我更喜欢 "standings",因为我相信这在您的域中是真实存在的。但是如果你想在没有额外上下文的情况下反映资源的数据结构,你可以使用像
这样的拼写GET /api/v1/leagues/{league-id}/players?orderBy=position
客户端发送给您的请求正文中的数据表示不是您的域模型中实体的序列化,它是发送给您的域模型的消息的序列化。