Questions tagged «api-design»

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

14
您是否应该将后端编写为API?
今天,我对我们的MVC应用程序进行了热烈的讨论。我们有一个用MVC(ASP.NET)编写的网站,它通常遵循在视图中执行某些操作的模式->击中控制器->控制器构建模型(调用获取数据的Manager,在该模型中构建模型控制器方法本身)->模型去查看->冲洗并重复。 他说我们的代码太紧密了。例如,如果我们还需要桌面应用程序,则将无法使用现有代码。 他说的解决方案和最佳实践是构建一个API,然后在您的API之上构建您的网站,然后构建一个桌面应用程序,移动应用程序等非常简单。 由于种种原因,这对我来说似乎是个坏主意。 无论如何,我似乎无法通过谷歌搜索找到任何讨论这种做法的东西。是否有人对优缺点有任何了解,为什么要这样做,为什么不应该这样做或需要进一步阅读? 我认为这是一个坏主意的一些原因: 太抽象了,无法通过API运行后端。您正在尝试使其过于灵活,这将使其变得难以处理。 MVC中内置的所有内容似乎都无用,例如角色和身份验证。例如,[授权]属性和安全性;您将不得不自己动手。 您的所有API调用都需要附加安全信息,并且您将必须开发令牌系统等等。 您将必须为程序将要执行的每个功能编写完整的API调用。您几乎要实现的每种方法都需要使用API​​。每个用户的Get / Update / Delete,以及每个其他操作的变体,例如更新用户名,将用户添加到组等,等等,每个将是一个不同的API调用。 当涉及到API时,您会丢失各种工具,例如接口和抽象类。WCF之类的东西对接口的支持非常微弱。 您有一个创建用户或执行某些任务的方法。如果要创建50个用户,则只需调用50次即可。当您决定将此方法用作API时,本地Web服务器可以命名管道连接到它,也没有问题-您的桌面客户端也可以访问它,但是突然间,您的批量用户创建将涉及在Internet上锤击该API 50次,不好 因此,您必须创建一个批量方法,但实际上您只是在为桌面客户端创建它。这样,您最终不得不a)根据与其集成的API修改API,而不能直接与其进行集成,b)做更多的工作来创建一个额外的功能。 YAGNI。除非您专门计划编写两个功能相同的应用程序,例如一个Web和一个Windows应用程序,否则这将是大量的额外开发工作。 当您无法端对端进行调试时,调试会困难得多。 许多独立的操作将需要大量的来回操作,例如,某些代码可能会吸引当前用户,检查该用户是否具有管理员角色,获取该用户所属的公司,获取其他成员的列表,并将其全部发送出去一封电邮。这将需要大量的API调用,或者为您想要的特定任务编写定制方法,而该定制方法的唯一好处是速度快,但缺点是不灵活。 可能还有其他一些原因,这些都不在我脑海中。 在我看来,除非您真的需要两个相同的应用程序,否则确实不值得。我也从未见过这样构建的ASP.NET应用程序,您必须编写两个单独的应用程序(API和您的代码),并同时对它们进行版本控制(如果您的用户页面有一个新字段,则d必须同时更新API和您使用的代码,以确保不会产生不良影响,或进行大量额外的工作以保持其健壮性)。 编辑:一些不错的回应,现在真的开始对这一切意味着什么有了一个好主意。因此,为了扩展我的问题,您将如何构建一个MVC应用程序以遵循此API结构? 例如,您有一个显示有关用户信息的网站。在MVC下,您可以: 视图-(CS)HTML页面,其中显示一个UserViewModel控制器-调用GetUser()并创建一个UserViewModel,并将其传递给具有GetUser方法的视图管理器类(与您的API相似)。 控制器执行GetUser(),但您也需要桌面应用程序。这意味着您的GetUser需要通过某种API公开。您可能需要TCP连接,或者是WCF,或者可能是Remoting。您还需要一个将是RESTful的移动应用程序,因为持久性连接不稳定。 那么,您是否会为每个API编写一个API,一个具有方法GetUser()的WCF Web服务,而代码恰好return new UserManager().GetUser()呢?和做同样事情的MVC 4 Web API方法呢?在继续直接在您的MVC控制器方法中调用GetUser时? 还是您会选择适用于所有三个应用程序的解决方案(Web api REST服务)并在其上构建所有内容,因此所有三个应用程序都进行API调用(对本地计算机的mvc调用)。 这仅仅是理论上的完美场景吗?我可以看到以这种方式进行开发的开销很大,尤其是如果您必须以一种允许您以RESTful方式进行操作的方式进行开发时。我认为其中一些已包含在答复中。 编辑2:在阅读更多内容之后,我在下面提出了一条评论,我认为这可能会解释它。我认为这个问题有点棘手。如果您将后端编写为API,让我感到困惑,我认为应该有一个单一的Web服务,所有东西(MVC应用程序,桌面应用程序,移动应用程序)都可以调用来完成工作。 我得出的结论是,您真正应该做的是确保业务逻辑层正确分离。查看我的代码,我已经这样做了-控制器将调用GetUser()管理器,然后从中创建一个视图模型以使用View进行渲染。因此,实际上,业务逻辑层是一个API。但是,如果要从桌面应用程序调用它,则需要编写WCF服务之类的内容以方便调用它。即使仅调用GetUser()一个包含代码的WCF方法return MyBusinessLayer.GetUser()就足够了。因此,API是业务逻辑,而WCF / Web api等只是让外部应用程序调用它的一小部分代码。 因此存在一些开销,因为您必须根据需要将业务逻辑层包装在不同的API中,并且必须为希望其他应用程序执行的每个操作编写API方法,此外,您还需要找出一种进行身份验证的方法,但在大多数情况下是相同的。将您的业务逻辑放在一个单独的项目(类库)中,您可能不会有任何问题! 希望这种解释是正确的。感谢它产生的所有讨论/评论。

4
什么是反腐败层?如何使用?
我正在尝试弄清“反腐败”层的真正含义。我知道这是一种过渡/解决旧代码或错误API的方法。我不明白的是它是如何工作的,是什么使它与不良层完全分离。 我已经进行了一些搜索,但是找不到任何简单的示例或解释,因此我正在寻找可以理解并可以通过简单示例进行解释的人员。可以满足我的问题的答案应该很简单(不一定要简短),并提供易于理解的实现和使用示例。 有关我的用例,请参见此问题。

7
搜索如何适合RESTful接口?
在设计RESTful接口时,请求类型的语义被认为对设计至关重要。 GET-列表收集或检索元素 PUT-替换集合或元素 POST-创建集合或元素 DELETE-好吧,erm,删除集合或元素 但是,这似乎没有涵盖“搜索”的概念。 例如,在设计一套支持求职网站的Web服务时,您可能具有以下要求: 获取个人招聘广告 GET来domain/Job/{id}/ 创建招聘广告 发布到domain/Job/ 更新职位广告 PUT到domain/Job/ 删除招聘广告 删除到domain/Job/ “获得所有工作”也很简单: GET来domain/Jobs/ 但是,工作“搜索”如何落入这种结构? 您可以声称这是“列表集合”的变体,并实现为: GET来domain/Jobs/ 但是,搜索可能很复杂,完全有可能产生一个生成长GET字符串的搜索。也就是说,在这里引用SO问题,使用GET字符串的长度超过2000个字符存在一些问题。 一个示例可能是多面搜索-继续“工作”示例。 我可能会在以下方面进行搜索-“技术”,“职位名称”,“学科”以及自由文本关键字,工作年龄,位置和薪水。 凭借流畅的用户界面和大量技术和职务,搜索可以包含大量方面的选择是可行的。 通过将此示例调整为简历而不是职位,可以带来更多的方面,您可以很容易地想象出搜索时选择了100个方面,甚至只是40个方面(每个方面50个字符)(例如,职务,大学名称,雇主名称)。 在那种情况下,可能需要移动PUT或POST,以确保将正确发送搜索数据。例如: 发布到domain/Jobs/ 但是从语义上讲,这是创建集合的指令。 您也可以说这将表示为搜索的创建: 发布到domain/Jobs/Search/ 或(如下面的燃烧语法所建议) 发布到domain/JobSearch/ 从语义上看,这似乎很有意义,但是您实际上并没有创建任何东西,而是在请求数据。 因此,从语义上讲,这是一个GET,但不能保证GET支持您所需要的。 因此,问题是-尝试尽可能地遵循RESTful设计,同时确保我保持在HTTP的限制之内,最适合搜索的设计是什么?

14
解决方案应该是尽可能通用的还是尽可能具体的?
假设我有一个具有“类型”属性的实体。可能有20多种可能的类型。 现在,我被要求实现一些允许从A-> B更改类型的方法,这是唯一的用例。 那么,我应该实现一些允许对类型进行任意更改的方法吗,只要它们是有效的类型?或者我应该只允许它根据要求从A-> B更改而拒绝其他任何类型的更改,例如B-> A或A-> C? 我从双方都可以看到优缺点,在将来出现类似要求的情况下,通用解决方案意味着工作量会减少,但这也意味着出错的可能性更大(尽管我们100%控制着调用方点)。 一种特定的解决方案不太容易出错,但是如果出现类似的要求,将来需要做更多的工作。 我一直在听到,优秀的开发人员应该尝试预期变化并设计系统,以便将来轻松扩展,这听起来像是通用解决方案? 编辑: 在我不太具体的示例中添加更多详细信息:在这种情况下,“通用”解决方案比“特定”解决方案需要的工作更少,因为特定解决方案需要对旧类型和新类型进行验证,而通用解决方案只需要验证新类型。

5
如果参数在语法上正确但违反业务规则,是否应该返回HTTP 400(错误请求)状态?
假设我有一个采用整数作为参数的REST端点: /makeWaffles?numberOfWaffles=3 在这种情况下,我希望数字是正数,因为我不能将华夫饼的数量设为负数(而请求0个华夫饼是浪费时间)。所以我想拒绝任何不包含正整数的请求。我还想拒绝超过某个最大整数的请求(现在说的是MAX_INTEGER)。 如果有人请求华夫饼的数量为非正数,我应该返回HTTP 400(错误请求)状态吗?我最初的想法是:对我来说,这不是有效的数字,无法完成请求。但是,RFC并未将业务规则作为抛出该规则的理由: 400(错误请求)状态代码表示服务器由于某些原因(例如格式错误的请求语法,无效的请求消息框架或欺骗性的请求路由)而被视为客户端错误,因此服务器无法处理该请求。 业务规则不属于这三个示例中的任何一个。从语法上讲,它是正确的,并且具有正确的框架,并且不是欺骗性的请求路由。 如果参数在语法上正确但违反业务规则,那么我应该返回HTTP 400(错误请求)状态吗?还是有更适合返回的身份?
56 api-design  http 

9
您是否应该防止来自外部API的意外值?
可以说,您正在编码一个从外部API接收输入的函数MyAPI。 该外部API MyAPI的合同规定其将返回string或number。 它是推荐的防范之类的东西null,undefined,boolean等即使它不属于API的一部分MyAPI?特别是,由于您无法控制该API,因此无法通过诸如静态类型分析之类的方法来做出保证,因此,安全起来总比对不起好。 我在考虑稳健性原则。


14
RESTful API设计。如果没有行,我应该返回什么?
我目前正在使用Slim Framework为社交网络编码API。我的问题是:当json结构中没有要返回的行时,最佳实践是什么? 可以说,此调用/ v1 / get / movies从表电影名称返回2行: [ {"name": "Ghostbusters"}, {"name": "Indiana Jones"} ] 但是,然后我调用了/ v1 / get / books,该表中没有行。我应该只返回一个空结构吗? [ ] ...或者消息和错误代码会更好吗? [ "errors": { "message": "no matches found", "code": 134 } ] 哪个更好的做法?(该API将在iOS和Android应用中使用)谢谢!

6
许多小请求与几个大请求(API设计)
我目前正在与一个组织一起从事以下项目: 客户端 -通过REST API从主服务器获取数据。 服务器 -通过第三方API向其他各种服务器请求数据 第三方API-无法控制的向服务器提供数据的服务(Reddit,Hackernews,Quora等) 出于争论的目的,假设客户端首先需要每个第三方API的项目列表。从该列表中,将选择一个项目,此时客户需要查看该项目的全部内容以及对该项目的响应(即评论)。我试图在三个选项之间做出选择: 点菜 用这种方法,我的服务器上将有3个单独的端点:一个用于获取项目列表,一个用于获取项目的主要内容,以及一个用于获取项目的响应。 优点:我从来没有发出比我需要更多的请求,请求应该很小,因此通常它们应该更快。 缺点:我必须提出很多要求。从列表中选择一个项目后,用户可能必须先等待才能看到主要内容,然后再等待更长的时间才能看到响应 服务器端缓存 在此请求中,我将对服务器进行一次调用以“获取”所有源的所有数据。然后,数据将被缓存在服务器上。然后,客户端将具有与以前相同的REST终结点,但是在两次调用之间不会有太多等待,因为我的服务器已经拥有了数据,只需要将其提供给客户端即可。 优点:仍然易于在客户端实现,但没有延迟问题 缺点:更多涉及服务器端,第一次调用可能要花很长时间。 客户端缓存 除了客户端只向服务器发出一个请求外,此方案与上一个相似:将所有数据提供给我。从这里开始,客户有责任保存数据并正确使用它们。 优点:易于服务器实施,在首次通话后非常快速 缺点:第一次调用将非常缓慢,客户端实现更为复杂 我不确定哪种方法是最好的,或者不确定是否缺少明显的解决方案。任何建议将不胜感激!

3
为什么PATCH方法不是幂等的?
我对此很纳闷。 假设我有一个user资源id和name字段。如果我想更新一个字段,我可以像这样对资源进行PATCH请求 PATCH /users/42 {"name": "john doe"} 然后应用程序将更新用户42的名称。 但是,如果我重复此请求,结果会有所不同吗? 根据RFC 5789 PATCH既不安全也不具有幂等性

6
有必要遵循防御性编程实践以获取永远不会公开获得的代码?
我正在编写纸牌游戏的Java实现,因此我创建了一种特殊的Collection类型,称为“区域”。不支持Java的Collection的所有修改方法,但是Zone API中有一种方法,该方法move(Zone, Card)可将Card从给定的Zone移到其自身(由package-private技术实现)。这样,我可以确保没有任何卡被带出区域并消失。它们只能移到另一个区域。 我的问题是,这种防御性编码有必要吗?这是“正确的”,并且感觉像是正确的做法,但这并不意味着Zone API永远不会成为某些公共库的一部分。这只是给我的,所以这有点像是在保护我自己的代码,以免仅使用标准Collections可能会提高效率。 我应该把这个区域创意带到多远?谁能给我一些建议,让我考虑在我编写的类中保存合同,特别是对于那些不会真正公开可用的类,应该考虑些什么?

3
DOM有什么不好的地方?
我一直在听到人们(尤其是Crockford)说DOM是一个糟糕的API,但并没有真正证明这一说法的合理性。除了跨浏览器不一致之外,为什么认为DOM如此糟糕还有哪些原因?

8
为什么java.util.ArrayList允许添加null?
我不知道为什么java.util.ArrayList允许添加null。在任何情况下我都想添加null到ArrayList吗? 我问这个问题是因为在一个项目中,我们有一个错误,其中一些代码正在添加null到,ArrayList并且很难发现该错误在哪里。显然NullPointerException抛出了a ,但是直到其他代码尝试访问该元素时才抛出。问题是如何找到添加null对象的代码。如果ArrayList在要添加元素的代码中引发异常,那会更容易。

1
REST API响应中的null与缺少键
在我的应用程序中说,有些用户给我们他们的姓氏,有些则没有。在REST API响应中,首选哪个主体: 具有“空”值: {"firstName": "Bob", "lastName": null} 或只是缺少的钥匙: {"firstName": "Bob"}
40 rest  api-design  json 

11
REST API是否应该返回500 Internal Server Error以指示查询引用了不存在的对象?
我正在使用REST API,该API驻留在为大量IoT设备处理数据的服务器上。 我的任务是使用API​​查询服务器以收集有关所述设备的特定性能信息。 在一个实例中,我获得了可用设备及其对应标识符的列表,然后稍后使用那些标识符(GUID)向服务器查询更多详细信息。 服务器正在500 Internal Server Error对这些ID之一返回a 进行查询。在我的应用程序中,引发了异常,并且我看不到有关该错误的详细信息。如果我使用Postman更仔细地检查响应,则可以看到服务器在包含以下内容的正文中返回了JSON: errorMessage: "This ID does not exist"。 忽略服务器提供ID开头的事实-这对于开发人员是一个单独的问题。 REST API是否应返回,500 Internal Server Error以报告查询引用了不存在的对象?在我看来,HTTP响应代码应严格参考REST调用的状态,而不是API的内部机制。我希望200 OK响应中包含错误和描述,这是所讨论的API专有的。 在我看来,取决于REST调用的结构,期望值可能存在差异。 考虑以下示例: http://example.com/restapi/deviceinfo?id=123 http://example.com/restapi/device/123/info 在第一种情况下,设备ID作为GET变量传递。404或500表示/restapi/deviceinfo找不到路径()或导致服务器错误。 在第二种情况下,设备ID是URL的一部分。我会更了解404 Not Found,但仍可以根据路径的哪些部分被解释为变量还是端点来争论。

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.