分离REST JSON API服务器和客户端?

我要从头开始创建一堆网络应用程序。(详见http://50pop.com/code)我希望他们能够从许多不同的客户端访问:前端网站,智能手机应用程序,后端web服务,等等。所以我真的想为每一个都提供一个JSON REST API。

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

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

一起在铁轨上

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

正方观点:很多先例。伟大的标准&;很多这样做的例子。

反对:不一定希望API与web应用相同。不喜欢if/then respond_with switch方法。混合两种非常不同的东西(UI + API)。

Rest服务器+ javascript重客户端

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

我喜欢API和amp的分离;客户端。聪明的人说这是正确的选择。理论上很好。看起来很前卫,令人兴奋。

反对:没有太多先例。这方面做得好的例子不多。公开的例子(twitter.com)让人感觉迟钝。甚至正在改变这种方法。

休息服务器+服务器端HTML客户端

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

我喜欢API和amp的分离;客户端。但提供简单的HTML5是相当万无一失的&不是client-intensive。

反对:没有太多先例。这方面做得好的例子不多。框架也不支持这一点。不知道该怎么处理。

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

71731 次浏览

我更倾向于选择第二条和第三条。主要是因为第一条违反了关注点的分离,并且混合了各种各样的东西。最终,你会发现需要有一个没有匹配HTML页面的API端点/等等,你会在同一个代码库中遇到HTML和JSON端点混合的麻烦。它变得一团糟,即使它是MVP,你最终也不得不重写它,因为它太混乱了,甚至不值得挽救。

采用#2或#3可以让你拥有一个完全相同(在大多数情况下)的API。这提供了很大的灵活性。我对Backbone/ember/whatever/etc.js还没有百分之百的信心。我认为这很棒,但正如我们在twitter上看到的那样,这并不是最优的。但是…推特也是一家巨兽公司,拥有数亿用户。因此,任何改进都会对各个业务部门的各个领域的底线产生巨大影响。我认为这个决定比速度本身更重要,他们不让我们参与其中。但这只是我的个人观点。然而,我并不轻视骨干和它的竞争对手。这些应用程序使用起来很棒,非常干净,反应灵敏(大多数情况下)。

第三种选择也有一定的吸引力。这就是我遵循帕累托原则(80/20规则)的地方,让20%的主标记(反之亦然)在服务器上呈现,然后让一个漂亮的JS客户端(backbone/etc)运行剩下的部分。你可能不会通过JS客户端与REST api进行100%的通信,但如果有必要的话,你会做一些工作来让suer体验更好。

我认为这是一个“视情况而定”的问题,答案是“这取决于”你在做什么,你在为谁服务,以及你希望他们得到什么样的体验。我认为你可以选择2个或3个或者它们的混合。

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

优点:

  • 尖端的/令人兴奋
  • 好处多多:API为你自己的web客户端、移动客户端、第三方访问等提供了基础。
  • 极其快速站点加载/页面转换

缺点:

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

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

对web前端人员的一些想法(这是这个架构所具有的所有新事物/挑战):

  • CoffeeScript。更容易生成高质量的代码。
  • 骨干。组织逻辑和活跃社区的好方法。
  • HAMLC。Haml + CoffeeScript模板=> JS。
  • 萨斯

我们已经为我们的前端开发构建了一个名为“Spar”(单页应用Rocketship)的工具,它实际上是Rails为单页应用开发调整的资产管道。我们将在接下来的几周内在我们的github页面上开放源代码,同时还有一篇博客文章解释如何使用它和更详细的整体架构。

更新:

至于人们对Backbone的担忧,我认为他们被高估了。骨干是一个组织原则,而不是一个深层框架。Twitter的网站本身就是一个Javascript的巨兽,覆盖了数百万用户的每一个角落。传统浏览器,在实时加载推文,垃圾收集,显示大量多媒体等。在我见过的所有“纯”js网站中,Twitter是一个奇怪的。有许多通过JS交付的令人印象深刻的复杂应用程序表现得非常好。

体系结构的选择完全取决于您的目标。如果您正在寻找支持多个客户端的最快方式,并有机会接触到优秀的前端人才,那么投资一个独立的API是一个很好的方法。

我的3个月项目已经进行了2个月,采用了你在这里概述的第二种方法。我们使用一个RESTful API服务器端,前端是backbone.js。js管理模板,jQuery处理AJAX和DOM操作。对于旧的浏览器和搜索蜘蛛,我们已经退回到服务器端渲染,但是我们使用的是与使用Mozilla Rhino的Handlebars前端相同的HTML模板。

我们选择这种方法有很多不同的原因,但我们非常清楚,因为它还没有在大范围内得到证明,所以它有点冒险。尽管如此,到目前为止一切都进行得很顺利。。

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

让项目的这两个部分彼此完全独立是选择这个基础设施的关键考虑因素。如果您正在寻找一种架构,可以在没有任何依赖的情况下混搭不同的独立资源,那么这种方法值得一试。

恐怕我不是Ruby的人,所以我不能评论其他方法。有时候冒险一下是可以的。其他时候最好谨慎行事。你会根据项目的类型来了解自己。

祝你选对了。也热衷于看别人分享什么。

我们使用#3的以下变体: 制作一个JSON-only REST API服务器。制作一个HTML网站服务器。HTML web服务器不是REST API服务器的客户端。相反,这两家公司是同行。在表面下不远的地方,有一个内部API提供两个服务器所需的功能。< / p >

我们不知道有任何先例,所以这是一种实验。到目前为止(即将进入测试阶段),它的效果相当不错。

我喜欢#3,当我的网站不是100%的CRUD实现我的数据。这种情况尚未发生。

我更喜欢sinatra,只会把应用程序分成几个不同的机架应用程序与不同的目的。我会做一个API特定的机架应用程序,将涵盖我需要的API。然后可能是一个用户机架应用程序,将呈现我的网页。有时该版本会在需要时查询API,但通常它只关心html站点。

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

下面是一个使用多个机架应用程序的非常简单示例。我在那里添加了一个jquery的快速示例,让你看到它击中API应用程序。你可以看到sinatra和安装多个不同用途的机架应用程序是多么简单。

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

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

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

选项1

这无疑是最受欢迎的一个。但我发现实现是非常http的。每个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的大多数要点在这里也适用。

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

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

Twitter的情况下

据我所知,Twitter可能会在服务器上进行初始页面渲染,但对于页面更新,它仍然有一些API调用和客户端模板来操作DOM。所以在这种情况下,你需要维护两个模板,这增加了一些开销和复杂性。不是每个人都能负担得起这个选项,不像Twitter。

我们的项目Stack

我碰巧使用Python。我使用JsonRPC 2.0代替REST。我建议使用REST,尽管出于各种原因我喜欢JsonRPC的想法。我使用下面的库。考虑选项2/3的人可能会觉得有用。

  • 一个快速的web微框架-
  • 前端服务器:Nginx
  • 客户端MVC: Knockout.js
  • 其他相关工具/lib:

    我的结论和建议

    选项3 !

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

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

我使用node.js作为客户端的后端和一些模块来帮助我。我在这个过程中有点早期,但基础已经设置好了,这是一个检查数据确保它全部呈现正确的问题。这是我正在使用的:

  • Express for the app's foundation.
    . 李(https://github.com/visionmedia/express) < / >
  • 读取数据请求 李(https://github.com/mikeal/request) < / >
  • 在服务器端渲染的模板下划线。我在客户端上重用这些 李(https://github.com/documentcloud/underscore) < / >
  • UTML包装下划线的模板,使它们与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)
  • <李>间距(https / / github.com/fat/smoosh) < br > …虽然我正在寻找grunt (https//github.com/cowboy/grunt)
  • 控制台跟踪(//github.com/LearnBoost/console-trace)。

不,我没有使用coffeescript。

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

(抱歉奇怪的链接,我太n00b堆栈溢出让我张贴那么多)

这里已经有一些很好的答案了——我肯定会推荐第2条或第3条——分离在概念上很好,在实践中也很好。

很难预测API上的负载和流量模式等事情,而我们看到的那些独立为API提供服务的客户更容易进行配置和扩展。如果你必须在人类的网络访问模式中做到这一点,那就不那么容易了。此外,你的API使用可能会比你的web客户端增长得更快,然后你就可以看到你的努力方向了。

在#2 #3之间,这真的取决于你的目标-我同意#2可能是web应用程序的未来-但也许你想要一些更直接的东西,如果那个频道只是众多频道中的一个!

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

优点:

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

  2. API是免费的。在你的应用程序中开放数据访问正在迅速成为一个标准功能。如果你从头开始使用一个API,你可以免费得到它。

  3. 清洁的分离。最好把你的应用想象成一个有客户端的API。当然,第一个也是最重要的客户端可能是web客户端,但它可以让你轻松创建其他客户端(iPhone, Android)。

缺点:

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

我现在想不出什么骗局了。

结论:如果你计划发布一个API, API + JS客户端是正确的选择。

另外,我还建议在发布API之前完整地记录它。编写gage .es API的过程确实帮助了我们进行imp操作

http://get.gaug.es/documentation/api/ < a href = " http://get.gaug.es/documentation/api/ " > < / >

我通常会选择第二个选项,使用Rails来构建API,并为JS的东西提供主干。你甚至可以使用ActiveAdmin免费获得一个管理面板。 我已经发布了几十个带有这种后端的手机应用程序。 但这在很大程度上取决于你的应用是否具有交互性。< / p >

我在上次RubyDay.it: http://www.slideshare.net/matteocollina/enter-the-app-era-with-ruby-on-rails-rubyday中做了关于这种方法的演示

对于第三个选项,为了获得第二个的响应性,你可能想尝试pajax,因为Github做的。

我采用了一种混合的方法,我们使用Sinatra作为基础,ActiveRecord / Postgress等来提供页面路由(细长模板),公开web应用程序可以使用的REST API。在早期的开发中,像填充选择选项这样的事情是通过helper渲染到精简模板中完成的,但当我们接近生产时,这就变成了对REST API的AJAX调用,因为我们开始更关心页面加载速度等等。

在Slim中很容易渲染出来的东西以这种方式处理,而东西(填充表单,从jQuery接收表单POST数据。验证的submitHandler等,显然都是AJAX)

测试是一个问题。现在我被难住了。

我个人更倾向于选择(3)作为解决方案。我的前雇主(家喻户晓的名字)几乎所有的网站都在使用它。这意味着你可以找一些了解Javascript、浏览器特性等的前端开发人员来编写你的前端代码。他们只需要知道“curl xyz,你会得到一些json”,然后他们就开始了。

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

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

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

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

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

同构渲染和渐进增强。这也是你选择第三个选项的原因。

同构呈现表示使用与客户端代码相同的模板来生成服务器端标记。选择具有良好的服务器端和客户端实现的模板语言。为您的用户创建完全烘烤的html并将其发送到线上。也要使用缓存。

渐进增强意味着一旦你下载了所有的资源,你就可以开始执行客户端执行和渲染以及事件监听,你可以确定客户端功能。为了可访问性和向后兼容性,尽可能使用无功能客户端脚本的功能。

是的,当然要为这个应用程序功能编写一个独立的json api。但不要太过分,为静态html文档那样工作得很好的东西编写json api。

REST服务器+ javascript为主的客户端是我在最近的工作中遵循的原则。

REST服务器实现在node . js + 表达 + MongoDB(非常好的编写性能)+ 猫鼬ODM(非常适合建模数据,包括验证)+ CoffeeScript(我现在去ES2015),这对我来说工作得很好。与其他可能的服务器端技术相比,Node.js可能相对年轻,但它使我能够编写集成了支付的可靠API。

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

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

Ember核心团队正在开发FastBoot,它可以让你在服务器端(node.js具体)执行你的JavaScript Ember逻辑,并发送预渲染的应用程序HTML(通常在浏览器中运行)给用户。这是伟大的搜索引擎优化和用户体验,因为他不会等待那么长时间的页面显示。

安贝CLI是一个很好的工具,可以帮助你组织你的代码,它在不断增长的代码库中扩展得很好。烬也有它自己的插件生态系统,你可以选择从各种安贝插件。你可以很容易地抓取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)感觉迟缓&甚至在切换 这种方法。< / p >

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

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

这样做的一个优点是API服务器可以独立于web服务器进行扩展。如果你有多个客户端,那么网站就不需要像web服务器那样扩展,因为一些客户端是基于手机/平板电脑或桌面的。

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

一个非常好的问题,我很惊讶,因为我认为这是一个非常普遍的任务,现在我会有足够的资源来解决这个问题,然而事实并非如此。

我的想法如下: -创建一些在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

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