您是否应该将后端编写为API?


322

今天,我对我们的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方法,此外,您还需要找出一种进行身份验证的方法,但在大多数情况下是相同的。将您的业务逻辑放在一个单独的项目(类库)中,您可能不会有任何问题!

希望这种解释是正确的。感谢它产生的所有讨论/评论。


25
您能否揭露您认为这是个坏主意的原因?如今,我必须承认,我认为没有理由不这样做。除其他优点外,它还使您可以轻松地将应用程序移植到不同的平台,并在不触摸后端代码的情况下就可以在前端实现极大的灵活性……
Laurent S.15年

12
@SLC:当您说API时,您是指Web服务API,例如SOAP或REST接口吗?因为您应该使后端成为API,但不应该使它成为Web服务。
JacquesB 2015年

7
@IanNewson“例如,一个移动应用程序往往功能较少。” 我从未听说过令人信服的理由,为什么移动应用程序应成为二等公民……(但每个人似乎都是这样做的)
Michael

3
@IanNewson那时可能只是我...但是我总是发现自己因无法在移动设备上做某事或其他事情而受挫,以至于我很少在移动设备上做些什么
Michael

11
您说YAGNI适用,但是我的经验是应用程序或者每两年重新编写一次UI,或者每个人都抱怨他们确实需要一个。如果我们不会因为新的前端技术到来而失去业务逻辑,那肯定会很好。
corsiKa 2015年

Answers:


282

是的你应该。

它不仅使您的后端可重复使用,而且可以提供更高的安全性和更好的设计。如果您将后端作为单个系统的一部分进行编写,那么您正在进行的单片设计将很难扩展,替换或增强。

一个领域,这是受欢迎的时刻是在微服务。后端被分成许多小(甚至大)服务,每个服务都提供客户端系统使用的API。如果您想象在应用程序中使用许多第三方数据源,您会意识到您可能已经在这样做了。

另一个好处是,每个服务的构建和维护可以移交给不同的团队,他们可以向其中添加不影响其他任何生产产品的团队的功能。只有完成并发布服务后,您才开始向产品添加功能以使用它们。这样可以使开发更加顺畅(尽管总体上可能会变慢,但您往往会获得更好的质量和易于理解的内容)


编辑:确定,我看到了你的问题。您将API视为远程库。不是。将服务视为更多的数据提供服务。您调用该服务以获取数据,然后在本地对该数据执行操作。要确定用户是否已登录,您可以调用“ GetUser”,然后查看该'logged on'值。(带有该示例的YMMV当然)。

您创建批量用户的示例只是在找借口-此处没有区别,您在单片系统中所做的一切仍然可以在服务体系结构中完成(例如,您将把一组用户传递给批量创建,或者一次创建。您仍然可以对服务进行完全相同的操作)。

MVC已经基于隔离服务的概念,只有MVC框架将它们捆绑到单个项目中。这并不意味着您会失去任何东西,除了框架为您提供的捆绑的帮助程序之外。使用不同的框架,您将不得不使用不同的帮助器。或者,在这种情况下,您可以自己滚动(或使用库直接添加它们)。

调试也很容易-您可以单独对API进行彻底测试,因此无需对其进行调试(并且可以端到端进行调试,Visual Studio可以同时附加到多个进程)。

诸如执行安全性的额外工作之类的事情是一件好事。当前,如果您将所有代码捆绑到您的网站中,那么如果黑客能够访问它,那么他们还可以访问包括DB在内的所有内容。如果将其拆分为一个API,除非他们也对API层进行了黑客攻击,否则黑客将无法对您的代码做太多工作-这对他们来说将是非常困难的(曾经想知道攻击者如何获得所有网站用户或抄送详细信息的庞大列表?这是因为他们入侵了OS或Web服务器,并且它直接连接到数据库,从而可以select * from users轻松地运行“ ”。

我要说的是,我已经看到许多这样写的网站(和客户端服务器应用程序)。当我在金融服务行业工作时,没有人会写一个网站,一方面是因为它存在太多的安全风险,另一方面是因为很多开发都是基于GUI(而不是稳定的后端数据处理)的漂亮的GUI系统。使用服务风格的体系结构很容易将DP系统作为网站公开。

2nd编辑:关于主题的一些链接(对于OP):

请注意,在网站上下文中谈论这些内容时,应该将Web服务器视为表示层,因为它是客户端调用其他层,并且还因为它构造了发送到浏览器进行渲染的UI视图。这是一个很大的主题,有许多方法可以设计您的应用程序-以数据为中心或以域为中心(我通常认为以域为中心是“纯粹的”,但YMMV),但这全都归结为介于两者之间的逻辑层您的客户和您的数据库。如果您认为中间层,API层等同于您的模型,则有点像MVC,只是模型不是数据库的简单包装,它更丰富并且可以做更多的事情(例如,从2个数据源聚合数据, -处理数据以适合API,缓存数据等):


2
从建筑宇航员的角度来看这是肯定的吗?我可以从服务的角度理解您的第二段和第三段,但是我们正在谈论的是GetUser,CreateUser,IsUserLoggedIn和数百个微小的函数,这些函数以前是单行代码,可以转换为API调用。
NibblyPig

12
假设您将其编写为网站,那么所有这些微小的功能都无法像您想象的那样具有交互性,因此在构造页面时,您必须获取数据并将其缓存在本地(或将其作为可能过时的数据传递给网站)。客户,视系统而定)。在很多情况下,您必须将设计从“按需响应”更改为“预先预期”,但是大多数系统将进行API调用。将您的API设计为粒度较小,以数据为中心,因此IsUserLoggedOn不必是API调用,只需要一个“ GetUserDetails”,然后在本地进行检查即可。
gbjbaanb 2015年

5
我们在我最后的工作场所使用了这种方法,效果很好。我们的主要产品是一个Web应用程序,但是我们能够创建一个桌面应用程序甚至Excel工作表,它们可以访问与我们的Web应用程序相同的Web服务来处理所有数据,并向客户公开这些服务,以便他们对他们编程。
2015年

2
这还有另一个好处:您可以向网站客户公开后端API。在我们公司,我们做到了这一点,一些大型软件公司的客户(在我们的主机上试用了后端)付了钱,将后端全部包装为自托管产品。根据产品的不同,一些客户对前端贴面的兴趣较小,而对您的产品实际功能(后端)的兴趣更大。那是另一种出售的产品。
Reid 2015年

2
这也使使用Web服务中的相同逻辑变得更加容易。我们的团队一直认为我们永远不必做的事情之一...这也使单元测试变得更加容易。
ps2goat

87

您可能无法避免构建API。即使您构建“仅一个网站”,它仍将需要以某种方式从后端获取其数据。但是,您决定执行此操作,这就是您实际的 API。

知道这一点,真正的问题不是是否要构建API,而是如何构建它。您可以作为临时对象即时进行操作 -实际上,许多网站正是以这种方式构建的-或者您可以精心设计使其可以在其他情况下使用。在这种情况下,很明显您的同事是对的:您应该先做API,然后在其上构建您的网站。

但是,正如您指出的那样,这带来了一些担忧。要解决这些问题:

太抽象了,无法通过API运行后端。您正在尝试使其过于灵活,这将使其变得难以管理。

这取决于您的操作方式。正如乔治·波利亚(GeorgePólya)在其出色的著作《如何解决》中指出的那样,通常“更普遍的问题可能更容易解决”。这称为发明人悖论。在编程的情况下,它通常通过关注点分离的方式起作用:您的后端不再需要关心放入和取出的数据的格式,因此其代码可以更加简单。您的数据解析器和渲染器不必再担心它们创建的数据会发生什么,因此它们也可以变得更简单。通过将代码分解为更多可管理的块,所有这些工作。

MVC中内置的所有内容似乎都无用,例如角色和身份验证。例如,[授权]属性和安全性;您将不得不自己动手。

我承认,我很难同情那些拒绝学习工具的人。仅仅因为您不了解它们的用途并不意味着它们是无用的,并且当然并不意味着您应该自己动手使用。恰恰相反; 您了解替代方案之前,您不应该滚动自己的工具,以便可以确保解决与替代方案相同的问题(即使仅以您自己的方式)。

考虑一下Linus Torvalds,他以编写Linux最著名,但同时也写了git:如今是世界上最受欢迎的版本控制系统之一。他设计中的驱动因素之一是对Subversion的强烈反对(另一个非常流行的VCS,可以说是git编写时最受欢迎的一种)。他决心采取Subversion可以采取的一切措施,并在可能的范围内以不同方式解决这些问题。为此,他必须自己成为Subversion的专家,以使他能够理解相同的问题领域并采用不同的方法。

或者,在学习工具的过程中,您可能会发现自己仍然是有用的,不需要替换。

您的所有API调用都需要附加安全信息,并且您将必须开发令牌系统等等。

是。这是应该的。

您将必须为程序将要执行的每个功能编写完整的API调用。您几乎要实现的每种方法都需要使用API​​。每个用户的Get / Update / Delete,以及每个其他操作的变体,例如更新用户名,将用户添加到组等,等等,每个将是一个不同的API调用。

不必要。这就是像REST这样的体系结构发挥作用的地方。您可以确定应用程序使用的资源以及适用于这些资源的有意义的操作,然后实施这些资源而不必担心其他资源

当涉及到API时,您会丢失各种工具,例如接口和抽象类。WCF之类的东西对接口的支持非常微弱。

相反,使用API​​时接口变得更加重要,而不是。它们出现在您将它们渲染成的表示中。如今,大多数人为此指定基于JSON的格式,但是只要指定得当,您就可以使用所需的任何格式。您可以在后端将此格式的调用输出呈现出来,然后将其解析为前端所需的任何内容(可能是相同类型的对象)。开销很小,灵活性方面的收益也很大。

您有一个创建用户或执行某些任务的方法。如果要创建50个用户,则只需调用50次即可。当您决定将此方法用作API时,本地Web服务器可以命名管道连接到它,也没有问题-您的桌面客户端也可以访问它,但是突然间,您的批量用户创建将涉及在Internet上锤击该API 50次,不好 因此,您必须创建一个批量方法,但实际上您只是在为桌面客户端创建它。这样,您最终不得不a)根据与其集成的API修改API,而不能直接与其进行集成,b)做更多的工作来创建一个额外的功能。

创建现有方法的批量版本几乎不是我所说的“更多工作”。如果您不担心原子性之类的问题,则批量方法可能只不过是原始方法的一个非常薄的前端而已。

YAGNI。除非您专门计划编写两个功能相同的应用程序,例如一个Web和一个Windows应用程序,否则这将是大量的额外开发工作。

不,YANI(您已经需要它)。我如上所述。唯一的问题是要投入多少设计工作。

当您无法端对端进行调试时,调试会困难得多。

您为什么不能端对端地步入正轨?

但更重要的是,能够以一种易于识别的格式来回检查数据,从而消除了所有显示残影,实际上使调试变得容易而不是困难。

许多独立的操作将需要大量的来回操作,例如,某些代码可能会吸引当前用户,检查该用户是否具有管理员角色,获取该用户所属的公司,获取其他成员的列表,并将其全部发送出去一封电邮。这将需要大量的API调用,或者为您想要的特定任务编写定制方法,而该定制方法的唯一好处是速度快,但缺点是不灵活。

REST通过处理完整的对象(使用REST理论的术语使用资源),而不是对象的单个属性来解决此问题。要更新用户名,请获取用户对象,更改其名称,然后将用户放回原位。您也可以在更改用户名的同时进行其他更改。更一般的问题变得更容易解决,因为您可以消除所有用于更新对象的各个属性的单个调用:只需加载并保存它。

在某些方面,这与硬件方面的RISC体系结构没有什么不同。RISC和CISC(其前身)之间的主要区别之一是,CISC体系结构倾向于包括许多直接在内存上运行的指令,而RISC体系结构倾向于主要在寄存器中运行:在纯RISC体系结构中,唯一的内存操作是LOAD(将某些内容从内存复制到寄存器中)和STORE(从寄存器中获取一个值并将其放入内存中)。

您可能会认为这意味着要花更多的时间从寄存器到内存,这会降低计算机的速度。但是实际上,情况恰恰相反:处理器(客户端)在两次访问内存(服务器)之间进行了更多工作,这就是加速的来源。

长话短说:您的同事是对的。这是要走的路。作为一项前期工作的交换,它将大大简化您网站的代码,实现与其他网站和应用程序的更好集成。那是值得付出的代价。

进一步阅读:

  1. REST API设计-资源建模

7
即使这些都具有事实上的 API。他们倾向于使其他许多开发人员感到恐惧,但是它们都是相同的API。只是设计不是很好。
2015年

7
这导致了一个非常差劲的API:太差劲了,以至于很多人甚至根本不认为它是API。但是它仍然定义了前端与后端交互的方式,尽管这种方式可能很粗糙。将其视为API有助于了解做好它的重要性。
2015年

1
我认为Linus之所以成为git是因为Linux社区反对使用用于内核的商业Bitkeeper DVCS。
gbjbaanb 2015年

2
您的第一句话消除了我的所有困惑。我将术语API与Web服务相关联,这就是我如此困惑的主要原因。
NibblyPig 2015年

4
@IanNewson:有一种方法可以与代码交互,称为http。它可能有很多不相关的要求,并返回了许多不相关的数据,但这就是使它成为糟糕的API的原因。
jmoreno 2015年

63

我知道微服务现在风行一时,但并不总是值得的。是的,目标是松散耦合代码。但这不应该以更痛苦的开发周期为代价。

一个很好的中间立场是在您的解决方案中创建一个单独的数据项目。数据项目将是.NET类库。然后,您的ASP.NET MVC项目将添加对数据库的引用,并且所有模型将从数据项目中提取。然后,当需要创建桌面或移动应用程序时,您可以引用相同的代码。因此它可能不是官方的API,但可以作为一个API使用。如果要使其作为API可以访问,则可以创建一个简单的Web项目,充当数据项目的包装器。

Microsoft一直在推广这个概念,他们将其称为可移植类库


13
我必须维护一个将逻辑放在UI层中的项目,调用相同的共享数据结构。因此,我不得不修复一个bug 三十次(“如果再次需要使用相同的逻辑,我们将复制并粘贴!不需要API”)。如果有一个逻辑层(现在有),只需要一个修复就足够了。
SJuan76 2015年

1
除了将该库包装到其自己的NuGet包中并托管自己的NuGet包feed / server之外,此答案也是一个不错的方法。您无需担心冗长的网络,可以使所有调用都在线程本地(因此速度更快),再加上通过NuGet向类库中引入正确的版本,可以使其他团队在升级时具有灵活性。
Greg Burghardt

34

不,你不应该。如果您没有立即计划创建访问同一后端的替代前端(例如移动或桌面应用或单独的Web应用),那么您不应该引入Web服务层。YAGNI

始终希望松散耦合(以及高内聚性),但这是一种设计原则,并不意味着您必须物理上将不同服务器上的对象分开!设计不良的服务API可能会跨服务器边界创建紧密耦合,因此拥有API不能保证松散耦合。

如果将来会出现对服务API的需求,那么您随时可以在此点进行介绍。只要您将代码保持良好的分层(数据访问和业务逻辑与UI逻辑完全分开),现在就不难介绍。当设计满足实际要求时,最终的设计将更好。


注意我假设问题是您是否应该创建Web服务 API。这个问题只说了API,但是API也只能表示一个库的接口,因此,根据定义,每个层当然都将具有一个API。最重要的是,您的业务逻辑和数据访问层应在设计级别与UI逻辑完全分开,但是如果不需要,则不应引入Web服务层。


8
设计不好的东西都是不好的。建立一个API不会花费更多的时间,并且可以适应未来的发展。如今,适应变化的能力至关重要,可以更好地建立强大的基础来满足您甚至不知道但可能比您想像的要早的任何需求……
Laurent S.15年

9
@Bartdude:为了“面向未来”而引入不必要的复杂性,以期未来不会到来,这只是在浪费资源。
JacquesB 2015年

6
@Bartdude添加一个api肯定是更多的时间。不知道您如何认为可以提出其他要求。
伊恩·纽森

13
“您不应该引入Web服务层” API!= Web服务。如果您的API具有业务逻辑,则可以在某个时候将该API作为Web服务公开。但是,这不是一个先决条件。
Celos

2
@JacquesB:...因此,如果不确定不确定是否需要功能,则实际上不会开发功能。我从YAGNI那里了解到这一点。然而,架构不是功能,错误的架构选择可能(很可能会)导致惨痛的失败。我再次假设这种讨论甚至可能发生,有时不是出于预算,上市时间,资源或缺乏知识的原因而发生的情况……我想我们可以完全同意不同意,尽管我了解您的观点,因为我经常和自己进行同样的讨论^ _ ^
Laurent S.

29

我公司有一个这样构建的应用程序。最初,我们被委托为另一个开发人员正在创建的前端使用API​​构建后端。当其他开发人员无法开发该前端时,我们也被委托构建前端。尽管此方法肯定有好处,但有一个巨大的缺点:成本。由于要维护的代码更多,并且还要部署两个单独的系统,因此初始构建的成本将大大提高,而持续的维护成本将更高。由于额外的成本,这应该始终是业务决策,开发人员不应一时兴起。

对此,我估计上面提到的项目由于这种方法而要多花费20%。您没有描述您正在为哪种公司工作的项目类型,但是如果您是一家初创公司产品的制造商,那么交付额外的成本可能就是交付一些使您的产品更强大的功能之间的区别成功。

另一个原因(至少不是普遍地)是,如果或当您决定创建第二个接口时,很少有一对一的功能映射。例如,如果您制作一个移动应用程序,它们往往功能较少。这意味着您的某些API方法将永远不会被重用。因此,与您的同事达成的折衷办法是,在您之间决定最关键/最关键的调用,并将这些调用添加到API中,并对其他所有操作使用更传统的方法。

要考虑的另一点是,您的同事说您将无法重用现有的代码,如果您将业务逻辑分开,那是不正确的。您只需要围绕内部API创建一个瘦Web服务包装器,这并不是一项特别大的任务。认为您可以将Web Service层重用于另一前端而根本不做任何更改是很天真。


22

这取决于应用程序类型和您所在的市场类型。

采取这种方式会有一些权衡和好处。一个方法比另一方法更好不是一个明确的答案。

我将从个人经验谈起。我是2007年决定采用此方向工作的代码库的人。该代码库现在大约有一百万行代码,其中一半是隐藏在大量Web服务背后的服务器代码。 API的另一半是客户群,桌面原生,桌面Web,移动,后端集成等……这个决定并非没有缺点,但是有20/20的事后见识,我可以说我会再做一次。让我指出一些涉及的取舍。

好处

  • 灵活性。无论是构建移动应用程序以增强桌面体验,还是与SAP后端集成的请求,都已经很容易调用API,这一切都变得更加容易。当您获得足够多的这些请求时,您将有机地朝着API方向发展,唯一的问题是它前面是否有标准的Web服务,或者它是否是量身定制的内部API。

  • (团队的)可伸缩性。在我们的案例中,我们有许多不同的开发人员组,所有开发人员都在此API的基础上构建。我们甚至拥有专门的API团队,他们与不同的小组进行交谈,总结需求,并从中构建通用的API。到了现在,我们甚至都没有被告知人们是在API之上构建东西,而不是每个人都对我们公司有用。

  • 安全。在代码库的不安全部分和安全部分之间进行清晰的划分有助于推断安全性。将UI和后端代码混在一起往往会使事情变得混乱。

权衡取舍

  • 灵活性。您必须完成将“正确”构建到API中的工作。从UI代码内部快速运行数据库查询以解决特定问题是不可能的。而且,实际上可重用的API必须考虑很多用例,以至于快速解决方案通常是错误的解决方案。该API的发展灵活性越来越差,尤其是因为那里已经有太多客户端代码(因此,我们正在过渡到版本化的API)。

  • 初始开发速度。毫无疑问,首先开发API较慢。只有在API之上构建了足够多的客户端时,您才能赢回它。但是随后您发现,在API变得足够通用之前,您需要3种不同的客户端实现。我们发现大多数最初的API设计都是错误的,因此不得不大力修改有关如何构建Web服务的准则。

红鲱鱼

您提到了一堆。实际上,它们实际上并不重要。

  • 抽象。您的API变得足够抽象,可以覆盖您的产品需要服务的所有用例,仅此而已。即使没有Web服务,您也将具有执行此操作的内部API,或者有很多重复的代码。与复制相比,我更喜欢抽象。

  • 放弃服务器端MVC堆栈。如今,一段时间后,几乎每个系统都需要一个移动应用程序。然后,当您构建Web服务以迎合该移动应用程序时,无论如何都要弄清楚如何在API上下文中进行身份验证和授权。实际上,只有一种方法(在Web服务中)可以完成工作。

  • 批量操作。通常通过创建一个批量API来解决,该API启动后端作业并返回作业ID以进行状态查询。没什么大不了的。

  • 调试。我发现总体上来说,对系统进行故障排除变得稍微容易一些。您仍然可以在前端和后端代码中都设置断点,因此在实践中并没有那么困难,并且您可以构建自动的api测试并对用于监视生产系统的api进行检测。

  • 很多独立的操作。这是您如何设计事物的问题。如果您坚持使用纯CRUD API,那么可以,您将遭受此问题的困扰。但是,通常可以使用一些CQRS API进行扩充,如果您确定自己拥有一个内部API,并且该服务是前端的,那么您可以轻松地重用该内部API为那些特定的对象构造服务场景的。

综上所述

在足够不同的上下文中使用的系统中,API会自然发展,因为它是满足所有需求的最简单方法。但是肯定有一个YAGNI案例。需要权衡取舍,直到有道理才有意义。关键是不要教条主义,对架构的不同方法持开放态度,以满足产品不断变化的需求。


有趣的读物,您能否详细说明在设计API时做错了什么以及学到了什么?
aaaaaaaaaaaaaa 2015年

3
三个主要错误是:(1)使api过于适合主ui的需求;(2)使用会话在多个请求之间建立状态(我们逐渐变得无会话);(3)仅支持使用generate命令db id作为标识符,其中用户可配置的代码通常是更好的标识符(对于与外部系统集成,通常,他们希望将标识符上载到我们的系统中,以供以后在api中使用,而不是相反)。这三者加上薄弱的文档和无益的错误消息使该API在没有帮助的情况下无法使用。
Joeri Sebrechts

10

您的同事所描述的是面向服务的体系结构。这可能是一种极大的可扩展性,可测试性和理智的编码方式,但这实际上取决于您的工作。

SOA有一些重要的好处,我将尝试列举一下:

可扩展性

由于后端是解耦的,因此前端变成只是一系列模板,甚至是平面文件。从任何CDN上提供服务,平面文件都非常快捷,便宜。可以将它们缩小并预编译为静态HTML,然后在数据客户端进行填充。

您的API必须保持一致,但是如果超出现有技术,则可以交换使用更快的技术而不会破坏堆栈。例如,您可以在Go中重新制作它。您可以零散地重建它,并在服务器之间分散负载。只要接口保持不变,就可以抽象该技术。

可测性

MVC通常是从干净的开始,但实际上,控制器很少将注意力集中在单个资源上。控制器方法所做的事情越多,它们的可测试性就越差。

API避开了这个问题。每个API调用都会提取资源并提供资源。清洁且可测试。

保证分离关注点

您的前端和后端已完全离婚。您可以将前端交给其他开发人员或设计师。这是将MVC带到另一个层次。我确定您不想放弃MVC。SOA是MVC,但更是如此。

缺点

当然也有一些缺点。独石通常会更快地上手。这可能是您习惯的。它可能更适合您的堆栈。您的工具可能已针对整体创建进行了优化。

在我看来,这些都不是特别好的理由,如果您愿意,您不妨考虑进行重新设计。


到目前为止,这是最明确的答案。
托尼·恩尼斯

7

这里有很多很好的答案,所以我只添加自己的实施经验。

我这是怎么做的:

  • 创建一个处理所有/仅数据库交互的数据库访问层(通常使用手动SQL进行速度和控制,不使用ORM)。插入,更新,删除,选择...
  • 创建一个interfacevirtual class),以显示/增强我需要的API函数。他们将在实施后使用高度专业的DBAL函数来实现结果。它还可以帮助我在编译器级别强制执行A​​PI,从而确保Server + API实现具有内置的所有功能。
  • 创建一个第二层来实现该接口(这是实际的API)并强制执行安全性限制。您还可以在此处与外部API进行交互。
  • 网站将直接使用第二层(以提高性能),而无需通过远程访问的API (例如SOAP,JSON)
  • 构建了独立服务器,该服务器实现了该接口,并将第二层作为实际的远程可访问API公开给外部台式机/移动客户端(非网站访问)。它所做的只是解码请求,编码响应以及管理/断开客户端。它还支持推回功能,以将其他连接的对等方生成的事件大量通知客户端(网站通常不需要的功能)

因此,从技术上讲,API是第二层。您可以直接在网站上使用它,并通过服务器将其公开给远程客户端。代码被重用,并且没有可重用的代码块内联。(按此规则生存和消亡,一切都很棒)帮助进行可维护性,测试……一切。

您永远不会将网站连接到桌面/移动API服务器(除非您的网站是AJAX并在JSON上运行)。但是,如果网站在标记中呈现动态内容,则通过中间API可以提高您的性能。网站需要快速!远程客户端访问可能会稍微慢一些。

PS是的,随着更多的轮子一起工作,维护会稍微复杂一些,但从长远来看,它更容易。因此,如果您的项目打算生存一段时间并且有点复杂,请始终使用API​​。单独测试每个层也容易得多。


这听起来很酷,并且很有道理,尤其是在API类型的函数上放置一个接口。下次创建项目时,我将尝试此设置!
NibblyPig 2015年

6

争论的重点不是您是否应该使用API​​,而是“ API”实际上是什么。使用设计的API的唯一替代方法是使用一个随机的代码混乱的API。您写道,API使事情变得“过于灵活”,从而使事情变得难以管理。这表明对API是什么有一个彻底而彻底的误解。如果您和您的同事之间没有分享这种误解,那么您会因为争论完全不同的事情而浪费了很多时间。

通过不使用定义明确的API,您可以做任何您想做的事情。根据定义,这是最灵活的选择。而且,根据定义,“随便做什么”仍然是一个API。API 的唯一工作就是消除灵活性。通过消除灵活性,好的API会鼓励用户以类似的方式做类似的事情。

当然,不良的API可能会提供过多或过少的灵活性,甚至可能同时提供两种灵活性。一个设计不佳的API可能比“一切皆有”方法更快地杀死一个项目。但是,最佳实践只是让有能力的程序员与您的应用程序一起开发和发展API。

•很多独立的操作需要大量来回操作,例如一些代码可能会吸引当前用户,检查该用户是否具有管理员角色,获取该用户所属的公司,获取其他成员的列表,然后发送给他们所有电子邮件。这将需要大量的API调用,或者为您想要的特定任务编写定制方法,而该定制方法的唯一好处是速度快,但缺点是不灵活。

对一个不错的API要求的API调用数量可能为1。是的,它不灵活,但是为什么要使其灵活?


4

他说我们的代码太紧密了。例如,如果我们还需要桌面应用程序,则将无法使用现有代码。

那你呢?如果不是这样,那将是一个无关紧要的声明。

我想说的是,如果您打算在2015年构建一个应用程序,那么请认真考虑用户界面中涉及API而不是服务器生成的HTML页面的内容。既有明确的成本,也有明确的利益。

但是,如果您有一个现有站点,但没有具体计划具有几个不同的接口(据我所知),那么他的评论就无关紧要了。


4

简短版本:无论如何,您的控制器都有效地提供了API;尽管ASP.NET可能会掩盖这一点。

较长版本:

考虑一个基本的MVC Web应用程序,该应用程序提供有关啤酒的信息,并有选择地向您出售啤酒。路线是什么样的?

/sign_in
/sign_out
/beer
/beer/{beer_name}
/order
/order/{order_number}

在普通的网络应用中,可能会有一些辅助路线,例如:

/beer/new
/beer/{beer_name}/edit
/beer/{beer_name}/delete
/order/new
/order/{order_number}/edit
/order/{order_number}/delete

在Web API中,这些不是必需的,因为它们是通过HTTP方法推断出来的。

鉴于上述对称性,我认为这是一个非常令人信服的案例,因为您的API和Controller如此接近,以至于它们可能是同一个人。

在进行了一些挖掘之后,我确定这可能是您所处的状态,具体取决于您所使用的ASP.NET版本。较早的MVC 5和以前的版本缺少将两个实现完美地统一的约定和接口。在旧版本中,Web App return填充一个View,而API提供HttpResponse。但是,无论哪种情况,他们都会在语义上生成完全相同的响应

如果您使用的是MVC 6,则将两者都归入一个统一的控制器类中,该类可以很聪明地返回结果。我没有找到任何适合该模型的ASP示例代码,但是我发现了一些具有相同模式的Rails代码。考虑将此控制器用于Diaspora项目中的“点赞”。每个控制器的方法具有由“机智公约”定义的路由这里的API中的量向LCRUD。

但是,如果您阅读这些实现,则每个实现都可能响应HTML,Mobile HTML或JSON。这与查找视图的约定结合在一起,完全统一了Web App和Web API。您还将注意到,并非所有方法实际上都提供每个响应(这很有意义,因为UI可能需要API不会提供的方法,反之亦然)。

这是一个阻抗失配,因为ASP.NET有点晚才弄清楚了所有这些,而Rails接受了对称已经有一段时间了,而且很清楚。

推测:

您的同事可能是对是非,这取决于您使用的ASP版本。在旧的MVC版本下,API和App之间的差异可能确实使其成为“预先创建API”的“最佳实践”,因为ASP.NET的模型并未真正允许在那里进行良好的代码重用。

使用更新的代码,使用统一代码更加有意义,因为使用统一控制器基类使重用代码变得更加容易。

但是,无论哪种情况,控制器都是有效的API。


这个问题已经死了,但是我认为其他答案还不那么清楚。“您可能无法避免构建API。” 答案几乎是现场的,被接受的答案围绕着同一问题跳动。但是两者都没有以我觉得很明确的方式专门针对ASP。
杰森2015年

越多越多的人回答,他们有助于全面理解他人对此的看法。
NibblyPig 2015年

2

当我在2006年开始我的职业生涯时,.NET世界中这种类型的架构风靡一时。我参与了2000年代中期构想的3个独立项目,并在业务逻辑层和Web前端之间提供了Web服务。当然,这些天Web服务都是SOAP,但它仍然是相同的体系结构。所谓的好处是能够切换前端或后端,甚至开发桌面程序。最终,YAGNI被证明是正确的。我从未见过这种情况。一直以来,我只看到以这种方式拆分项目的成本。我什至最终从一个项目中删除了Web服务(花了半年时间在做其他事情的同时逐步删除了它),整个团队都很高兴。从那时起,我就再也没有尝试过这种方法,除非给出非常具体的理由,否则我不会。尝试该体系结构的5年经验告诉我,我将不需要它,而且没有专家告诉我相反的说法可以说服我。只有我需要的项目才能做到。

话虽如此,我确实努力在业务逻辑和控制器/演示者之间建立一层。例如,我有一个服务层,我从不公开可查询对象,对我所有的服务都使用接口,并将它们注入到具有IoC的控制器中。如果我的体系结构中需要Web服务,则可以以合理的成本进行介绍。我只是不想提前支付这笔费用。

我也很喜欢微服务的想法,但是我的理解是微服务意味着垂直模块而不是水平层。例如,如果您正在构建Facebook,则聊天功能将是一项单独的服务,分别部署在其自己的服务器上,等等。我鼓励这种独立的服务。


2

第三方会用吗? 是的,你应该

您打算在不久的将来重新使用它? 是的你应该。
您将成为第三方,拥有成文的-或成文的-或可由第三方使用的 API,将为您提供可靠的可重用性和模块化。

你着急吗? 不,你不应该。
事后重构比大多数方法和教师所预测和讲述的要容易和快捷。比起什么都不做,拥有有效的东西(即使内部设计不好,因为它会并且会被重构)更重要。(但具有令人难以置信的内部设计,哇)

由于某些原因,前端可能永远看不到今天? 是的,你应该
我添加这个原因是因为,这在我身上发生了很多。
至少我剩下的组件可以重用和重新分发等。


1

这里有很好的答案。我将此作为部分答案发布;作为评论也许会更好。但是,在很多帖子上贴相同的评论是不好的。

不能声称YAGNI是未创建API的原因。

该API是自然而逻辑的测试端点。因此,从第0天开始,就有两个使用API​​的应用程序:UI和测试套件。一个是给人类的,另一个是给机器的。他们一定是不同的。测试前端行为与测试后端行为大不相同。因此,技术以及可能的工具是完全不同的。该API允许将最佳工具用于这项工作。此外,借助API提供的分离功能,前端测试人员不必测试后端功能。

该API还有助于使前端编码器摆脱后端编码器的关注,反之亦然。这些是我们公司非常不同的技能。API使我们能够专注于最强的地方。

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.