372

我即将从头开始创建一堆网络应用程序。(有关概述,请参见http://50pop.com/code。)我希望它们能够从许多不同的客户端访问:前端网站、智能手机应用程序、后端 Web 服务等。所以我真的想要一个每个 JSON REST API。

此外,我更喜欢在后端工作,所以我梦想着只专注于 API,并聘请其他人来制作前端 UI,无论是网站、iPhone、Android 还是其他应用程序。

请帮助我决定我应该采取哪种方法:

一起在铁轨上

制作一个非常标准的 Rails 网络应用程序。在控制器中,执行 respond_with 开关,以提供 JSON 或 HTML。JSON 响应就是我的 API。

优点:很多先例。伟大的标准和许多以这种方式做事的例子。

缺点:不一定希望 API 与 Web 应用程序相同。不喜欢 if/then respond_with 切换方法。混合两种非常不同的东西(UI + API)。

REST SERVER + JAVASCRIPT-HEAVY 客户端

制作仅 JSON 的 REST API 服务器。使用 Backbone 或 Ember.js 作为客户端 JavaScript 直接访问 API,在浏览器中显示模板。

Pro:我喜欢 API 和客户端的分离。聪明的人说这是要走的路。理论上很棒。看起来很前沿和令人兴奋。

缺点:没有太多先例。这方面做得好的例子并不多。公共示例 (twitter.com) 感觉迟缓,甚至正在放弃这种方法。

REST 服务器 + 服务器端 HTML 客户端

制作仅 JSON 的 REST API 服务器。制作一个仅访问 REST API 的基本 HTML 网站客户端。更少的客户端 JavaScript。

Pro:我喜欢 API 和客户端的分离。但是提供纯 HTML5 是非常简单的并且不是客户端密集型的。

缺点:没有太多先例。这方面做得好的例子并不多。框架也不支持这一点。不知道如何处理它。

尤其是从经验中寻求建议,而不仅仅是理论上的建议。

4

18 回答 18

138

Boundless,我们深入研究了选项 #2,并将其推广给了成千上万的学生。我们的服务器是一个 JSON REST API(Scala + MongoDB),我们所有的客户端代码都是直接从 CloudFront 提供的(即:www.boundless.com 只是 CloudFront 的别名)。

优点:

  • 前沿/激动人心
  • 物超所值:API 为您自己的 Web 客户端、移动客户端、第 3 方访问等提供了基础。
  • 极快的网站加载/页面转换

缺点:

  • 没有更多的工作,对 SEO 不友好/准备就绪。
  • 需要一流的网络前端人员,他们准备好应对 70% javascript 的网站体验的现实以及这意味着什么。

我确实认为这是所有网络应用程序的未来。

对 Web 前端人员的一些想法(这是该架构赋予所有新事物/挑战的地方):

  • 咖啡脚本。更容易生成高质量的代码。
  • 骨干。组织逻辑和活跃社区的好方法。
  • 汉密尔顿。Haml + CoffeeScript 模板 => JS。
  • SASS

我们为我们的前端开发构建了一个称为“Spar”(单页应用程序火箭飞船)的工具,它实际上是 Rails 为单页应用程序开发调整的资产管道。我们将在接下来的几周内在我们的github页面上开源,并附上一篇博客文章,详细解释如何使用它和整体架构。

更新:

关于人们对 Backbone 的担忧,我认为他们被高估了。Backbone 与其说是一个深度框架,不如说是一个组织原则。Twitter 的网站本身就是一个巨大的 Javascript 野兽,涵盖了数百万用户和旧版浏览器的每一个角落,同时实时加载推文、垃圾收集、显示大量多媒体等。在我所有的“纯”js 网站中可见,Twitter 是个奇怪的人。有许多通过 JS 交付的非常复杂的应用程序运行良好。

您对架构的选择完全取决于您的目标。如果您正在寻找支持多个客户并获得优秀前端人才的最快方式,那么投资独立 API 是一个不错的选择。

于 2012-06-07T23:54:25.760 回答
49

问得很好。+1。当然,这对我来说是未来有用的参考。@Aaron 和其他人也为讨论增加了价值。与 Ruby 一样,这个问题同样适用于其他编程环境。

我使用了前两个选项。第一个用于众多应用程序,第二个用于我的开源项目Cowoop

选项1

这一款无疑是最受欢迎的一款。但我发现实现非常http-ish。每个 API 的初始代码都用于处理请求对象。所以 API 代码不仅仅是纯粹的 ruby​​/python/其他语言代码。

选项 2

我一直很喜欢这个。

此选项还意味着 HTML 不是在服务器上运行时生成的。这就是选项 2 与选项 3 的不同之处。但是使用构建脚本将其构建为静态 html。当在客户端加载时,这些 HTML 将调用 API 服务器作为 JS API 客户端。

  • 关注点分离是很大的优势。并且非常符合您(和我)的喜好,后端专家实现了后端 API,像通常的语言代码一样轻松地测试它们,而无需担心框架/http 请求代码。

  • 这实际上并不像在前端听起来那么困难。API 调用和结果数据(主要是 json)是否可用于您的客户端模板或 MVC。

  • 更少的服务器端处理。这意味着您可能会选择商品硬件/较便宜的服务器。

  • 更容易独立测试层,更容易生成 API 文档。

它确实有一些缺点。

  • 许多开发人员发现这过度设计且难以理解。因此,架构可能会受到批评。

  • i18n/l10n 很难。由于 HTML 本质上是生成的,构建时间是静态的,因此每种支持的语言都需要多次构建(这不一定是坏事)。但即便如此,您可能会遇到 l10n/i18n 附近的极端情况,需要小心。

选项 3

在这种情况下,后端编码必须与第二个选项相同。选项 2 的大部分要点也适用于此。

网页使用服务器端模板在运行时呈现。这使得 i18n/l10n 更容易使用更成熟/公认的技术。对于页面渲染所需的某些基本上下文(如用户、语言、货币等),可能会减少一次 http 调用。因此,服务器端处理随着渲染而增加,但可能会通过减少对 API 服务器的 http 调用来补偿。

现在页面是在服务器上呈现的,前端现在与编程环境更加紧密。对于许多应用程序来说,这甚至可能不是考虑因素。

推特案例

据我了解,Twitter 可能会在服务器上进行初始页面渲染,但对于页面更新,它仍然有一些 API 调用和客户端模板来操作 DOM。因此,在这种情况下,您需要维护双重模板,这会增加一些开销和复杂性。与 Twitter 不同,并非每个人都能负担得起这种选择。

我们的项目堆栈

我碰巧使用Python。我使用 JsonRPC 2.0 而不是 REST。我建议使用 REST,尽管出于各种原因我喜欢 JsonRPC 的想法。我使用以下库。考虑选项 2/3 的人可能会发现它很有用。

  • API Server:Python 一个快速的 Web 微框架 - Flask
  • 前端服务器:Nginx
  • 客户端 MVC:Knockout.js
  • 其他相关工具/库:

我的结论和建议

选项3!。

总而言之,我已经成功使用了选项 2,但现在为了简单起见倾向于选项 3。使用构建脚本生成静态 HTML 页面并使用专门提供静态页面的超快速服务器之一为它们提供服务是非常诱人的(选项 2)。

于 2012-06-08T09:15:42.337 回答
28

我们在构建 gaug.es 时选择了 #2。我负责 API(ruby、sinatra 等),而我的商业伙伴 Steve Smith 负责前端(javascript 客户端)。

优点:

  1. 快速平行移动。如果我在 Steve 之前工作,我可以继续为新功能创建 API。如果他在我之前工作,他可以​​很容易地伪造 API 并构建 UI。

  2. API 免费。对应用程序中的数据进行开放访问正迅速成为一项标准功能。如果您从头开始使用 API,您可以免费获得它。

  3. 干净的分离。最好将您的应用程序视为具有客户端的 API。当然,第一个也是最重要的客户端可能是 Web 客户端,但它可以让您轻松创建其他客户端(iPhone、Android)。

缺点:

  1. 向后兼容性。与您的直接问题相比,这与 API 更相关,但是一旦您的 API 出现,您就不能仅仅破坏它或者破坏所有客户端两个。这并不意味着你必须放慢速度,但这确实意味着你必须经常同时做两件事。添加到 API 或新字段是好的,但不应该在没有版本控制的情况下进行更改/删除。

我现在想不出缺点了。

结论:如果您打算发布 API,API + JS 客户端是必经之路。

PS 我还建议在发布之前完整记录您的 API。记录 Gaug.es API 的过程确实帮助我们实现了

http://get.gaug.es/documentation/api/

于 2012-06-12T01:03:00.990 回答
10

我更喜欢走#2和#3的路线。主要是因为#1 违反了关注点分离并且混合了各种东西。最终,您会发现需要一个没有匹配的 HTML 页面/等的 API 端点,并且您将在同一代码库中混杂 HTML 和 JSON 端点。它变成了一团糟,即使它的 MVP,你最终也必须重新编写它,因为它太乱了,甚至不值得挽救。

使用 #2 或 #3 可以让您完全拥有一个行为相同(大部分)的 API。这提供了很大的灵活性。我还没有在 Backbone/ember/whatever/etc.js 上 100% 售出。我认为它很棒,但正如我们在推特上看到的那样,这并不是最佳选择。但是... Twitter 也是一家公司的巨兽,拥有数亿用户。因此,任何改进都会对各个业务部门的各个领域的底线产生巨大影响。我认为决定不仅仅是速度,他们不会让我们参与其中。但那只是我的个人意见。但是,我并不低估骨干及其竞争对手。这些应用程序非常好用,非常干净且响应迅速(大部分情况下)。

第三种选择也具有一定的吸引力。这就是我遵循帕累托原则(80/20 规则)并在服务器上呈现 20% 的主要标记(反之亦然)的地方,然后让一个不错的 JS 客户端(骨干网/等)运行其余部分. 您可能不会通过 JS 客户端与 REST api 进行 100% 的通信,但如果有必要,您将做一些工作以使用户体验更好。

我认为这是“取决于”类型的问题之一,答案是“取决于”你在做什么,你在为谁服务,以及你希望他们获得什么样的体验。鉴于我认为您可以在 2 个或 3 个或它们的混合体之间做出决定。

于 2012-06-07T23:53:03.157 回答
7

我们使用 #3 的以下变体:制作仅 JSON 的 REST API 服务器。制作一个 HTML 网站服务器。HTML Web 服务器不像您的变体那样是 REST API 服务器的客户端。相反,两者是同行。在表面之下不远处,有一个内部 API 可提供两台服务器所需的功能。

我们不知道任何先例,所以它是一种实验性的。到目前为止(即将进入测试版)​​,它运行良好。

于 2012-06-08T00:10:59.707 回答
7

我目前正在将一个巨大的 CMS 从选项 1 转换为选项 3,并且进展顺利。我们选择在服务器端呈现标记,因为 SEO 对我们来说很重要,我们希望网站在手机上表现良好。

我将 node.js 用于客户端的后端,并使用一些模块来帮助我。我在这个过程中有点早,但基础已经建立,这是一个检查数据以确保一切正确呈现的问题。这是我正在使用的:

  • Express 为应用程序的基础。
    (https://github.com/visionmedia/express)
  • 请求获取数据。
    (https://github.com/mikeal/request)
  • 在服务器端呈现的下划线模板。我在客户端上重用这些。
    (https://github.com/documentcloud/underscore)
  • UTML 包装了 underscore 的模板以使它们与 Express 一起使用。
    (https://github.com/mikefrey/utml)
  • 前期收集模板,让您选择发送给客户的模板。
    (https://github.com/mrDarcyMurphy/upfront)
  • Express Expose 将获取的数据、一些模块和模板传递到前端。
    (https://github.com/visionmedia/express-expose)
  • Backbone 在吞下传递的数据后在前端创建模型和视图。
    (https://github.com/documentcloud/backbone)

这就是堆栈的核心。我发现其他一些有用的模块:

  • 斑点(https//github.com/trek/fleck)
  • 时刻(https//github.com/timrwood/moment)
  • 手写笔(https//github.com/LearnBoost/stylus)
  • smoosh (https//github.com/fat/smoosh)
    …虽然我正在研究 grunt (https//github.com/cowboy/grunt)
  • 控制台跟踪(//github.com/LearnBoost/console-trace)。

不,我没有使用咖啡脚本。

这个选项对我来说非常有效。后端的模型不存在,因为我们从 API 获得的数据结构良好,我将其逐字传递给前端。唯一的例外是我们的布局模型,我在其中添加了一个使渲染更智能、更轻量的属性。我没有为此使用任何花哨的模型库,只是一个在初始化时添加我需要的内容并返回自身的函数。

(对不起,奇怪的链接,我太多了堆栈溢出的 n00b 让我发布那么多)

于 2012-06-08T10:28:44.583 回答
7

我通常会选择第二个选项,使用 Rails 构建 API,并使用 JS 的主干。您甚至可以使用ActiveAdmin免费获得一个管理面板。我已经发布了数十个带有这种后端的移动应用程序。但是,这在很大程度上取决于您的应用程序是否具有交互性。

我在上届RubyDay.it上对这种方法做了一个介绍:http ://www.slideshare.net/matteocollina/enter-the-app-era-with-ruby-on-rails-rubyday

对于第三个选项,为了获得第二个选项的响应能力,您可能想像Github 一样尝试pajax 。

于 2012-06-21T13:16:58.837 回答
6

我进入一个为期 3 个月的项目大约 2 个月,该项目采用您在此处概述的第二种方法。我们使用一个 RESTful API 服务器端,前端有主干.js。Handlebars.js 管理模板,jQuery 处理 AJAX 和 DOM 操作。对于较旧的浏览器和搜索蜘蛛,我们已经退回到服务器端渲染,但我们使用与使用 Mozilla Rhino 的 Handlebars 前端相同的 HTML 模板。

我们出于许多不同的原因选择了这种方法,但非常清楚这有点冒险,因为它还没有得到广泛的证明。一切都一样,到目前为止一切都很顺利。

到目前为止,我们只使用了一个 API,但在项目的下一阶段,我们将使用第二个 API。第一个是处理大量数据,第二个更像是通过 API 的 CMS。

让项目的这两个部分完全独立运行是选择此基础架构的关键考虑因素。如果您正在寻找一种架构来混搭不同的独立资源而没有任何依赖关系,那么这种方法值得一看。

恐怕我不是 Ruby 人,所以我无法评论其他方法。有时冒险是可以的。其他时候最好安全地玩。您将根据项目的类型了解自己。

祝您在这里选择好运。也渴望看到其他人分享的内容。

于 2012-06-07T23:57:31.703 回答
4

当我的网站不会 100% 实现数据的 CRUD 时,我喜欢 #3。这还没有发生。

我更喜欢 sinatra,并将应用程序拆分为几个具有不同用途的不同机架应用程序。我将制作一个特定于 API 的机架应用程序,该应用程序将涵盖我对 API 的需求。然后也许是一个用户机架应用程序,它将展示我的网页。有时该版本会在需要时查询 API,但通常它只关注 html 站点。

我不担心,如果需要,只需从用户端进行持久层查询。我不太关心创建完全分离,因为它们通常最终服务于不同的目的。

这是一个使用多个机架应用程序的非常简单的示例。我在其中添加了一个快速的 jquery 示例,供您查看它访问 API 应用程序。您可以看到使用 sinatra 和安装具有不同目的的多个机架应用程序是多么简单。

https://github.com/dusty/multi-rack-app-app

于 2012-06-08T01:47:04.250 回答
1

这里已经有一些很好的答案——我肯定会推荐 #2 或 #3——这种分离在概念上是好的,但在实践中也是如此。

很难预测 API 上的负载和流量模式等内容,我们看到独立服务 API 的客户可以更轻松地进行配置和扩展。如果您必须使用人类 Web 访问模式来做这件事,那就不太容易了。此外,您的 API 使用最终可能会比您的 Web 客户端更快地扩展,然后您就可以看到将您的努力指向何处。

在 #2 #3 之间,这真的取决于你的目标——我同意 #2 可能是 webapps 的未来——但如果该频道只是其中之一,也许你想要更直接的东西!

于 2012-06-08T11:13:45.247 回答
1

对于 atyourservice.com.cy,我们使用服务器端渲染的页面模板,特别是为了覆盖 se 部分。并在页面加载后使用 API 进行交互。由于我们的框架是 MVC,所有控制器功能都复制到 json 输出和 html 输出。模板是干净的并且只接收一个对象。这可以在几秒钟内转换为 js 模板。我们始终维护服务器端模板,并根据请求重新转换为 js。

于 2014-03-08T12:29:15.523 回答
1

同构渲染和渐进增强。这就是我认为你在选项三中的目标。

同构渲染意味着使用与您在客户端代码中使用的相同模板在服务器端生成标记。选择具有良好服务器端和客户端实现的模板语言。为您的用户创建完全烘焙的 html 并将其发送到网络中。也使用缓存。

渐进增强意味着一旦您下载了所有资源并且您可以确定客户端功能,就开始进行客户端执行和渲染以及事件侦听。尽可能回退到功能性的无客户端脚本功能,以实现可访问性和向后兼容性。

是的,当然要为此应用功能编写一个独立的 json api。但不要走得太远以至于你为作为静态 html 文档工作的东西编写了一个 json api。

于 2015-06-06T08:10:34.090 回答
1

REST server + JavaScript-heavy client 是我最近工作中遵循的原则。

REST 服务器是在node.js + Express + MongoDB(非常好的编写性能)+ Mongoose ODM(非常适合建模数据,包括验证)+ CoffeeScript(我现在改用 ES2015)中实现的,这对我来说效果很好。与其他可能的服务器端技术相比,Node.js 可能相对年轻,但它使我能够编写集成支付的可靠 API。

我使用Ember.js作为 JavaScript 框架,大部分应用程序逻辑都在浏览器中执行。我使用SASS(特别是 SCSS)进行 CSS 预处理。

Ember 是由强大社区支持的成熟框架。它是一个非常强大的框架,最近在性能方面做了很多工作,比如全新的 Glimmer 渲染引擎(受 React 启发)。

Ember 核心团队正在开发FastBoot,让您可以在服务器端(特别是 node.js)执行 JavaScript Ember 逻辑,并将应用程序的预渲染 HTML(通常在浏览器中运行)发送给用户。这对于 SEO 和用户体验来说非常棒,因为他不会等待这么长时间来显示页面。

Ember CLI是一个很棒的工具,可以帮助您组织代码,并且可以很好地随着代码库的增长而扩展。Ember 也有自己的插件生态系统,您可以从各种Ember 插件中进行选择。您可以轻松获取 Bootstrap(在我的情况下)或 Foundation 并将其添加到您的应用程序中。

不是通过 Express 提供所有服务,我选择使用 nginx 来提供图像和 JavaScript 繁重的客户端。在我的情况下,使用 nginx 代理很有帮助:

upstream app_appName.com {
  # replace 0.0.0.0 with your IP address and 1000 with your port of node HTTP server
  server 0.0.0.0:1000;
  keepalive 8;
}

server {
  listen 80 default_server;
  listen [::]:80 default_server ipv6only=on;

  client_max_body_size 32M;

  access_log  /var/log/nginx/appName.access.log;
  error_log  /var/log/nginx/appName.error.log;

  server_name appName.com appName;

  location / {
     # frontend assets path
     root /var/www/html;
     index index.html;

     # to handle Ember routing
     try_files $uri $uri/ /index.html?/$request_uri;
  }

  location /i/ {
    alias /var/i/img/;
  }

  location /api/v1/ {
    proxy_pass  http://app_appName.com;

    proxy_next_upstream error timeout invalid_header http_500 http_502
http_503 http_504;
    proxy_redirect off;
    proxy_buffering off;
    proxy_set_header        Host            $host;
    proxy_set_header        X-Real-IP       $remote_addr;
    proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

Pro:我喜欢 API 和客户端的分离。聪明的人说这是要走的路。理论上很棒。看起来很前沿和令人兴奋。

我可以说它在实践中也很棒。分离 REST API 的另一个优点是您可以稍后将其重新用于其他应用程序。在完美的世界中,您应该能够将相同的 REST API 不仅用于网页,还可以用于移动应用程序(如果您决定编写一个)。

缺点:没有太多先例。这方面做得好的例子并不多。公共示例 (twitter.com) 感觉迟缓,甚至正在放弃这种方法。

现在情况看起来不同了。有很多做 REST API 的例子 + 许多客户使用它。

于 2015-09-27T14:25:27.127 回答
1

我决定为Infiniforms选择 Option #2 的架构,因为它提供了一种将 UI 与业务逻辑分离的好方法。

这样做的一个优点是 API 服务器可以独立于 Web 服务器进行扩展。如果您有多个客户端,则网站不需要像 Web 服务器那样扩展,因为某些客户端将基于手机/平板电脑或台式机。

这种方法还为您向用户开放 API 提供了良好的基础,尤其是当您使用自己的 API 为您的网站提供所有功能时。

于 2016-06-06T07:44:07.727 回答
1

一个非常好的问题,我很惊讶,因为我认为这是当今非常普遍的任务,因此我将有足够的资源来解决这个问题,但结果并非如此。

我的想法如下: - 创建一些在 API 控制器和 HTML 控制器之间具有共同逻辑的模块,而不返回 json 或呈现 html,并将该模块包含在 HTML 控制器和 API 控制器中,然后做任何你想做的事情,例如:

module WebAndAPICommon
    module Products

        def index
            @products = # do some logic here that will set @products variable
        end

    end
end


class ProductsController < ApplicationController
    # default products controlelr, for rendering HMTL pages 
    include WebAndAPICommon

    def index
        super
    end

end



module API
    class ProductsController
        include WebAndAPICommon

        def index
            super
            render json: @products
        end

    end
end
于 2016-07-06T13:54:23.220 回答
0

我采用了一种混合方法,我们使用 Sinatra 作为基础,使用 ActiveRecord / Postgress 等来提供页面路由(超薄模板),从而公开 Web 应用程序可以使用的 REST API。在早期开发中,诸如填充选择选项之类的事情是通过渲染到苗条模板中的助手来完成的,但是当我们接近生产时,这会被替换为对 REST API 的 AJAX 调用,因为我们开始更关心页面加载速度等等。

很容易在 Slim 中呈现的东西就是这样处理的,而且东西(填充表单,从 jQuery.Validation 接收表单 POST 数据submitHandler等,显然都是 AJAX)

测试是个问题。现在我很难将 JSON 数据传递给 Rack::Test POST test

于 2013-09-10T10:30:48.167 回答
0

我个人更喜欢选项(3)作为解决方案。它几乎用于我的前(家喻户晓)雇主拥有的所有网站。这意味着您可以找到一些了解 Javascript、浏览器怪癖和诸如此类的前端开发人员来编写您的前端代码。他们只需要知道“curl xyz,你就会得到一些 json”,然后他们就走了。

同时,您的重量级后端人员可以编写 Json 提供程序。这些人根本不需要考虑演示,而是担心不稳定的后端、超时、优雅的错误处理、数据库连接池、线程和扩展等。

选项 3 为您提供了一个良好、可靠的三层架构。这意味着你从前端吐出的东西是 SEO 友好的,可以使用旧的或新的浏览器(以及那些关闭 JS 的浏览器),如果你愿意,仍然可以是 Javascript 客户端模板(所以你可以做一些事情,比如用静态 HTML 处理旧浏览器/googlebot,但将 JS 构建的动态体验发送给使用最新 Chrome 浏览器或其他的人)。

在我见过的所有情况下,选项 3 都是一些 PHP 的自定义实现,不能在项目之间特别转移,更不用说进入开源领域了。我想最近 PHP 可能已经被 Ruby/Rails 取代了,但同样的事情仍然存在。

FWIW,$current_employer 可以在几个重要的地方使用选项 3。我正在寻找一个好的 Ruby 框架来构建一些东西。我确信我可以将大量 gem 粘合在一起,但我更喜欢单一产品,它广泛地提供模板、“curling”、可选身份验证、可选 memcache/nosql 连接缓存解决方案。在那里我找不到任何连贯的东西:-(

于 2013-12-02T10:37:10.220 回答
0

在 Rails 中构建 JSON API 是一流的,JSONAPI::Resources gem 为http://jsonapi.org规范的 API完成了繁重的工作。

于 2017-01-07T17:29:31.643 回答