Questions tagged «api-design»

应用程序编程接口(API)设计讨论了创建用于通用或公共用途的库的最佳实践。

5
REST API如何适合基于命令/操作的域?
在本文中,作者声称 有时,需要公开API中固有的非RESTful操作。 然后 如果一个API有太多的动作,则表明它是使用RPC观点设计的,而不是使用RESTful原理设计的,或者所讨论的API自然更适合RPC类型模型。 这也反映了我在其他地方阅读和听到的内容。 但是,我觉得这很令人困惑,我希望对此事有更好的了解。 示例I:通过REST接口关闭VM 我认为,有两种根本不同的方法来对虚拟机关闭建模。每种方式可能会有一些变化,但现在让我们集中讨论最基本的差异。 1.修补资源的状态属性 PATCH /api/virtualmachines/42 Content-Type:application/json { "state": "shutting down" } (或者,PUT在子资源上/api/virtualmachines/42/state。) VM将在后台关闭,并且在稍后的某个时间点(取决于关闭的成功与否)将成功,否则状态可能不会通过“关闭电源”在内部进行更新。 2.在资源的actions属性上进行PUT或POST PUT /api/virtualmachines/42/actions Content-Type:application/json { "type": "shutdown" } 结果与第一个示例完全相同。该状态将立即更新为“关闭”,并可能最终更新为“关闭电源”。 两种设计都是RESTful的吗? 哪个设计更好? 示例II:CQRS 如果我们有一个CQRS域,其中包含许多这样的“操作”(又称命令),它们可能潜在地导致多个聚合的更新,或者无法映射到具体资源和子资源上的CRUD操作? 我们是否应该在可能的情况下尝试建模尽可能多的命令,具体取决于在具体资源上创建或更新的具体资源(遵循示例I的第一种方法),其余部分使用“动作端点”? 还是应该将所有命令映射到动作端点(如示例I的第二种方法)? 我们应该在哪里划界线?设计何时变得不那么RESTful? CQRS模型是否更适合RPC之类的API? 据我了解,根据上面引用的文字。 从我的许多问题中可以看出,我对该主题有些困惑。您能帮我更好地了解它吗?

5
您如何最好地在REST API中表示双向同步?
假设系统中有一个带资源的Web应用程序,以及另一个具有类似资源的远程应用程序的引用,那么您如何表示双向同步操作,该操作将“本地”资源与“远程”资源同步? 例: 我有一个代表待办事项清单的API。 GET / POST / PUT / DELETE / todos /等 该API可以引用远程TODO服务。 GET / POST / PUT / DELETE / todo_services /等 我可以通过我的API作为代理通过远程服务来处理待办事项 GET / POST / PUT / DELETE / todo_services / abc123 /等 我希望能够在本地待办事项集和远程待办事项集之间进行双向同步。 以一种rpc的方式, POST / todo_services / abc123 / sync / 但是,在“动词很糟糕”的想法中,是否有更好的方法来表示此动作?

2
将现有项目添加到REST API中的集合的最佳模式是什么?
我正在设计一个实用的REST API,并且对如何最好地将现有实体添加到集合中有些困惑。我的域模型包括一个具有站点集合的项目。这是一个严格的多对多关系,我无需创建一个显式建模该关系的实体(即ProjectSite)。 我的API将允许使用者将现有站点添加到项目中。我挂断电话的地方是,我真正需要的唯一数据是ProjectId和SiteId。我最初的想法是: 1. POST myapi/projects/{projectId}/sites/{siteId} 但是我也想过 2. POST myapi/projects/{projectId}/sites 与作为JSON内容发送的Site实体。 选项1简单易用,但感觉不太正确,而且我还有其他关系无法遵循此模式,因此它增加了我的API的不一致性。 选项2感觉更好,但引起两个问题: 如果发布了新网站(SiteId = 0),我应该创建一个网站还是引发异常? 因为我只需要ProjectId和SiteId来创建关系,所以该站点可能发布的其他属性数据有误或缺失。 第三种选择是提供一个仅用于创建和删除关系的简单端点。该端点将期望仅包含ProjectId和SiteId的JSON有效负载。 你怎么看?
23 rest  api-design 

5
成功时返回true / false与void的函数,失败时抛出异常
我正在构建一个API,一个上传文件的函数。如果文件上传正确,此函数将不返回任何内容/无效,并且在出现问题时将引发异常。 为什么要例外而不是错误?因为在异常中,我可以指定失败的原因(无连接,文件名丢失,密码错误,文件描述丢失等)。我想构建一个自定义异常(带有一些枚举来帮助API用户处理所有错误)。 这是一个好习惯还是返回一个对象(内部包含布尔值,可选错误消息和错误枚举)更好?

2
是否应该仅通过查看代码就总是知道API在做什么?
最近,我一直在开发自己的API,随着对API设计的投入,我一直对如何改善API设计非常感兴趣。 出现了几个方面(不是我的API用户使用,而是在我对该主题的观察讨论中):一个人应该只通过查看调用API的代码来知道它在做什么。 例如,请参见GitHub上有关此讨论的讨论,例如: foo.update_pinned(true, true); 仅仅通过查看代码(不知道参数名称,文档等),就无法猜测它会做什么-第二个参数是什么意思?建议的改进措施如下: foo.pin() foo.unpin() foo.pin_globally() 这就清除了一切(我猜第二个参数是是否全局固定foo),在这种情况下,我同意后者肯定会有所改进。 但是我相信,在某些情况下,设置不同但与逻辑相关的状态的方法最好作为一个方法调用而不是单独的方法公开,即使您仅通过查看代码也不知道它在做什么。(因此,您必须求助于参数名称和文档以查明-如果我不熟悉API,我个人将始终这样做)。 例如,我SetVisibility(bool, string, bool)在FalconPeer上公开了一种方法,并且我承认只看了一下这一行: falconPeer.SetVisibility(true, "aerw3", true); 您将不知道它在做什么。它设置了3个不同的值来控制falconPeer逻辑上的“可见性” :仅接受接受密码的加入请求,然后回复发现请求。将其分为3个方法调用可能会导致API的用户设置“可见性”的一个方面而忘记设置其他设置,而我仅通过公开一种方法来设置“可见性”的所有方面而迫使他们考虑。此外,当用户想要更改一个方面时,他们几乎总是会想要更改另一个方面,现在可以在一个呼叫中进行更改。


4
为什么Java集合API没有最后一种方法?[关闭]
已关闭。这个问题是基于观点的。它当前不接受答案。 想改善这个问题吗?更新问题,以便通过编辑此帖子以事实和引用的形式回答。 5年前关闭。 这用于有序集合,例如java.util.List。语言设计者为什么不包括最后一种方法?我能想到的唯一原因是: 集合为空时的歧义(返回null或引发异常) API膨胀 还有其他原因吗?
19 java  api-design 

2
REST API设计:对API的多次调用与单次调用
我们正在开发用于电子商务网站的Rest API,它将由移动应用程序使用。 在应用程序的首页中,我们需要调用多个资源,例如滑块,顶级品牌,畅销产品,热门产品等。 进行API调用的两个选项: 单次通话: www.example.com/api/GetAllInHome 多个通话: www.example.com/api/GetSliders www.example.com/api/GetTopBrands www.example.com/api/GetBestSellingProducts www.example.com/api/GetTrendingProducts 其余api设计的最佳方法是哪种-一次或多次调用,说明优缺点? 哪个会花更多时间来响应请求?
19 rest  api  api-design  url 

4
数据库抽象-是否过高?
在接触了众多数据库抽象层之后,我开始怀疑每个库发明自己的不同范例来访问数据的意义何在。选择一种新的DAL感觉就像是在重新学习一种新的语言,通常我要做的只是说服该层输出我已经写在脑海中的SQL查询。 事实上,这甚至没有涉及可读性: # Exhibit A: A typical DAL rows = db(db.ips_x_users.ip_addr == '127.0.0.1') .inner_join(db.ips_x_users.user_id == db.users.id) .select(order=(db.ips_x_users.last_seen, 'desc'), limit=10) # Exhibit B: Another typical DAL rows = db.ips_x_users .join(db.users, on=db.ips_x_users.user_id == db.users.id) .filter(db.ips_x_users.ip_addr == '127.0.0.1') .select(sort=~db.ips_x_users, limit=10) # Exhibit C: A hypothetical DAL based on standard SQL syntax rows = …
18 database  sql  api-design  dsl 

4
为什么Java String没有静态字符串操作方法?
Java设计人员为什么不在类中创建字符串操作方法的静态版本java.lang.String?我指的是以下方法,但是问题也可以扩展到该类中的其他非静态方法。 concat(String) substring(int, int) replace(char, char) toLowerCase() replace(CharSequence, CharSequence) toLowerCase(Locale) replaceAll(String, String) toString() replaceFirst(String, String) toUpperCase() split(String) toUpperCase(Locale) split(String, int) trim() substring(int) 仅使用这些方法的非静态版本会在必须调用此方法的任何地方强制进行显式 null检查。例如,简单的调用example = example.trim()会导致NullPointerException异常如果String example = null。因此,程序员必须执行以下样板空检查: if (example != null) example = example.trim(); // OR: example = (example==null) ? null : example.trim(); example = (example==null) ? null …
17 java  api-design  null 

3
检测IEnumerable“状态机”
我刚刚读了一篇有趣的文章,《用C#收益回报变得太可爱了》 这让我想知道最好的方法是检测IEnumerable是否是实际的可枚举集合,或者它是使用yield关键字生成的状态机。 例如,您可以将DoubleXValue(来自本文)修改为以下内容: private void DoubleXValue(IEnumerable<Point> points) { if(points is List<Point>) foreach (var point in points) point.X *= 2; else throw YouCantDoThatException(); } 问题1)有更好的方法吗? 问题2)创建API时,我应该担心这一点吗?
17 c#  api-design 

3
什么时候应该在接口中使用string_view?
我正在使用一个内部库,该库旨在模仿拟议的C ++库,并且在过去几年中的某个时候,我看到其接口已从使用更改std::string为string_view。 因此,我忠实地更改了代码,以适应新的界面。不幸的是,我必须传递的是std :: string参数,以及返回的std :: string值。所以我的代码从这样的事情改变了: void one_time_setup(const std::string & p1, int p2) { api_class api; api.setup (p1, special_number_to_string(p2)); } 至 void one_time_setup(const std::string & p1, int p2) { api_class api; const std::string p2_storage(special_number_to_string(p2)); api.setup (string_view(&p1[0], p1.size()), string_view(&p2_storage[0], p2_storage.size())); } 除了更多的代码(可能搞砸了)之外,我真的看不到这种变化给我作为API客户端带来了什么。API调用不太安全(由于API不再拥有其参数的存储空间),可能保存了我的程序0的工作(由于编译器现在可以进行移动优化),即使确实保存了工作,也只能在启动后或在某个地方的大循环中,将不会并且永远不会完成的一些分配。不适用于此API。 但是,这种方法似乎遵循我在其他地方看到的建议,例如,以下答案: 顺便说一句,从C ++ 17开始,您应该避免传递const std :: string&,而推荐使用std :: …

2
何时在RESTful API中使用嵌套资源
我有两个资源:用户和链接。 用户可以具有几个与之关联的链接。我已经设计了RESTful API,以便您可以通过以下URI访问与用户关联的链接: /users/:id/links 但是,我总是需要一个仅用于链接的URI –有时我可能想要所有链接,无论用户是谁。 为此,我有: /links 听起来还好吗?有两个链接的URI吗? 我想知道是否应该使用URI来访问用户的链接,例如: /links/user/:id 要么 /links/?user=:id 这样,我只有一个链接资源。
16 api  rest  api-design 

3
REST API版本控制。每个API都有自己的版本
在URL中指定REST API的版本是很普遍的,特别是在路径的开头,例如: POST /api/v1/accounts GET /api/v1/accounts/details 但是,我还没有看到将版本与每个API关联的任何设计。换句话说,我们分别维护每个API的版本。即: POST /api/accounts/v2 GET /api/accounts/details/v3 使用这种方法,当需要中断更改时,我们可以增加特定API的API版本,而无需增加整个API的版本。 使用此样式而不是通用样式有什么弊端?

1
RESTful API和i18n:如何设计响应?
我们正在设计一个RESTful API,主要用于满足单个客户端的需求。由于其非常特殊的情况,此客户端必须发出尽可能少的请求。 API通过请求中的Accept-Language标头处理i18n。这适用于客户端需要做的所有事情,除了一项功能外,在该功能中,客户端需要在所有可用的语言环境中存储对单个端点的请求响应。 我们是否可以以某种方式设计API,使客户端可以在单个请求中获取所有这些信息,而又不会破坏一致的,结构良好的RESTful API设计? 到目前为止,我们已经考虑的选项: 允许在Accept-Language标头中包含多个语言环境,并在响应中为所有请求的语言环境添加本地化版本,每个语言环境均以其ISO 639-1语言代码标识为密钥。 为该端点创建类似“?all_languages = true”的参数,并在响应中返回所有可用语言环境的本地化版本(如果存在该参数的话)。 (如果以上方法对我们都不起作用),将发出多个请求以从客户端获取所有本地化版本。 哪一个是最好的选择?
15 rest  api  api-design  http 

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.