关于ruby on rails 3:单独的REST JSON API服务器和客户端?

Separate REST JSON API server and client?

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

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

请帮助我决定采用哪种方法:

TOGETHER IN RAILS

Make a very standard Rails web-app. In the controller, do the respond_with switch, to serve either JSON or HTML. The JSON response is then my API.

Pro: Lots of precedent. Great standards & many examples of doing things this way.

Con: Don't necessarily want API to be same as web app. Don't like if/then respond_with switch approach. Mixing two very different things (UI + API).

REST SERVER + JAVASCRIPT-HEAVY CLIENT

Make a JSON-only REST API server. Use Backbone or Ember.js for client-side JavaScript to access API directly, displaying templates in browser.

Pro: I love the separation of API & client. Smart people say this is the way to go. Great in theory. Seems cutting-edge and exciting.

Con: Not much precedent. Not many examples of this done well. Public examples (twitter.com) feel sluggish & are even switching away from this approach.

REST SERVER + SERVER-SIDE HTML CLIENT

Make a JSON-only REST API server. Make a basic HTML website client, that accesses the REST API only. Less client-side JavaScript.

Pro: I love the separation of API & client. But serving plain HTML5 is quite foolproof & not client-intensive.

Con: Not much precedent. Not many examples of this done well. Frameworks don't support this as well. Not sure how to approach it.

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


在"无限"中,我们深入研究了选项2,并将其推广到数千名学生身上。我们的服务器是一个JSONRESTAPI(scala+mongodb),我们的所有客户机代码都直接从CloudFront中提供(例如:www.infranged.com只是CloudFront的别名)。

赞成的意见:

  • 尖端/刺激
  • 这是你的一大利好:API为你自己的Web客户机、移动客户机、第三方访问等提供了基础。
  • 极快的网站加载/页面转换

欺骗:

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

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

对Web前端人员的一些想法(在这里,所有新的需求/挑战都被赋予了这个架构):

  • 咖啡描述。更容易生成高质量的代码。
  • 骨干。组织逻辑和活跃社区的好方法。
  • 哈姆尔克。haml+coffeescript模板=>js。
  • 萨斯

我们已经为前端开发构建了一个称为"spar"(单页应用程序Rocketship)的工具,它实际上是Rails为单页应用程序开发调优的资产管道。在接下来的几周内,我们将在Github页面上开放寻源,同时发布一篇博客文章,详细说明如何使用它以及总体架构。

更新:

关于人们对脊梁骨的关注,我认为他们被高估了。骨干结构与其说是一个深层框架,不如说是一个组织原则。Twitter的网站本身就是一个巨大的javascript野兽,它覆盖了数百万用户和传统浏览器的每一个角落,同时实时加载tweet、垃圾收集、显示大量多媒体等。在我见过的所有"纯"JS网站中,Twitter是一个很奇怪的网站。通过JS交付的许多非常复杂的应用程序运行良好。

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


问得很好。+ 1。当然,这对我将来很有用。同时@aron和其他人也为讨论增加了价值。和Ruby一样,这个问题同样适用于其他编程环境。

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

Option 1

This one is no doubt the most popular one. But I find implementation are very much http-ish. Every API's initial code goes in dealing with request object. So API code is more than pure ruby/python/other language code.

Option 2

I always loved this.

This option also implies that HTML is not runtime generated on server. This is how option 2 is different from option 3. But are build as static html using a build script. When loaded on client side these HTML would call API server as JS API client.

  • Separation of concerns is great advantage. And very much to your liking (and mine) backend experts implement backend APIs, test them easily like usual language code without worrying about framework/ http request code.

  • This really is not as difficult as it sounds on frontend side. Do API calls and resulting data (mostly json) is available to your client side template or MVC.

  • Less server side processing. It means you may go for commodity hardware/ less expensive server.

  • Easier to test layers independently, easier to generate API docs.

It does have some downsides.

  • Many developers find this over engineered and hard to understand. So chances are that architecture may get criticized.

  • i18n/l10n is hard. Since HTML is essentially generated build time are static, one needs multiple builds per supported language (which isn't necessarily a bad thing). But even with that you may have corner cases around l10n/i18n and need to be careful.

Option 3

Backend coding in this case must be same as second option. Most points for option 2 are applicable here as well.

Web pages are rendered runtime using server side templates. This makes i18n/l10n much easier with more established/accepted techniques. May be one less http call for some essential context needed for page rendering like user, language, currency etc. So server side processing is increased with rendering but possibly compensated by less http calls to API server.

Now that pages are server rendered on server, frontend is now more tied with programming environment. This might not be even a consideration for many applications.

号Twitter案例

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

我们的项目组合

我碰巧用的是Python。我使用JSONRPC 2.0而不是REST。我建议休息,尽管出于各种原因我喜欢JSONRPC的想法。我使用下面的库。有人认为2/3方案是有用的。

  • API服务器:python a fast web micro framework-flask
  • 前端服务器:nginx
  • 客户端MVC:knockout.js
  • 其他相关工具/libs:
    • 滑动分页
    • 货币核算.js
    • Webshim:跨浏览器polyfill
    • 主管:客户端路由
    • sphc:html生成

我的结论和建议

选项3!.

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


我们在建造Gaug.es时选择了2。我在API(Ruby、Sinatra等)上工作,我的业务伙伴Steve Smith在前端(JavaScript客户机)上工作。

赞成的意见:

  • 平行快速移动。如果我先于史蒂夫工作,我可以继续为新特性创建API。如果他在我前面工作,他可以很容易地伪造出API并构建UI。

  • API免费。开放式访问应用程序中的数据很快成为一项标准功能。如果你从一开始就使用API,你可以免费得到它。

  • 清洁分离。最好把你的应用看作是客户端的API。当然,第一个也是最重要的客户机可能是一个网络客户机,但它可以让您轻松创建其他客户机(iPhone、Android)。

  • 欺骗:

  • 向后兼容。这与一个API比直接的问题更相关,但是一旦你的API出现了,你就不能仅仅打破它或者把你所有的客户机都打破了。这并不意味着你必须慢一点,但也意味着你必须经常同时做两件事。向API或新字段中添加是可以的,但不应该在没有版本控制的情况下进行更改/删除。
  • 我现在想不出更多的犯人了。

    结论:如果您计划发布一个API,那么API+JS客户机是一种可行的方法。

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

    http://get.gaug.es/文档/api/


    我喜欢走2和3的路线。主要是因为1违反了关注点的分离并混合了各种各样的东西。最终,您将发现需要有一个API端点,它没有匹配的HTML页面/etc,并且您将在同一代码库中遇到混合HTML和JSON端点的问题。它变成了一个惊人的混乱,即使它的最有价值球员,你最终将不得不重新写它,因为它非常混乱,它甚至不值得挽救。

    使用2或3可以让您完全拥有一个API,不管它的作用(大部分)如何。这提供了很大的灵活性。我还没有100%的主干网/ember/whatever/etc.js销售。我认为这很好,但正如我们在Twitter上看到的,这不是最佳的。但是…Twitter也是一个公司的巨兽,拥有数亿用户。因此,任何改进都可能对各业务部门的各个领域的底线产生巨大影响。我认为这项决定比单纯的速度更重要,他们不会让我们参与进来。但这只是我的意见。但是,我不认为主干网和它的竞争对手有任何折扣。这些应用程序非常好用,非常干净,响应能力非常强(大部分)。

    第三种选择也有一些有效的吸引力。在这里,我将遵循pareto原则(80/20规则),在服务器上呈现20%的主标记(反之亦然),然后让一个漂亮的JS客户机(主干网/etc)运行其余的标记。您可能没有通过JS客户机与RESTAPI 100%通信,但如果需要,您将做一些工作以使Suer体验更好。

    我认为这是一个"取决于"的问题,答案是"取决于"你在做什么,你在为谁服务,你希望他们获得什么样的经验。考虑到这一点,我认为你可以在2或3之间做出决定,或者两者的混合。


    我们使用3的以下变体:创建一个仅限JSON的RESTAPI服务器。创建HTML网站服务器。与您的变体不同,HTML Web服务器不是RESTAPI服务器的客户机。相反,他们是同龄人。在表面之下不远处,有一个内部API提供两个服务器所需的功能。

    我们不知道任何先例,所以这是实验性的。到目前为止(即将进入测试版),它已经运行得相当好了。


    我目前正在努力将一个巨大的CMS从选项1转换为选项3,而且进展顺利。我们之所以选择呈现标记服务器端,是因为SEO对我们来说意义重大,我们希望这些站点在移动电话上表现良好。

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

    • 为应用程序的基础表达。(https://github.com/visionmedia/express)
    • 请求获取数据。(https://github.com/mikeal/request)
    • 下划线模板,用于呈现服务器端。我在客户机上重用它们。(https://github.com/documentcloud/underline)
    • utml包装下划线的模板,使其与Express一起工作。(https://github.com/mikefrey/utml)
    • 预先收集模板,让我们选择发送到客户机的模板。(https://github.com/mrdarcymurphy/upfront)
    • express expose将获取的数据、一些模块和模板传递到前端。(https://github.com/visionmedia/express-expose)
    • 主干在吞咽传递的数据后在前端创建模型和视图。(https://github.com/documentcloud/主干网)

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

    • fleck(https//github.com/trek/fleck)
    • 力矩(https//github.com/timrwood/moment)
    • 手写笔(https//github.com/learnboost/stylus)
    • Smoosh(https//github.com/fat/smoosh)…尽管我在研究咕噜(https//github.com/cowboy/grunt)
    • 控制台跟踪(//github.com/learnboost/console trace)。

    不,我没有用咖啡描述。

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

    (对于奇怪的链接很抱歉,堆栈溢出让我无法发布那么多的n00b)


    我通常会选择第二个选项,使用Rails构建API,以及JS的主干。你甚至可以使用activeadmin免费获得一个管理面板。我已经提供了几十个带有这种后端的移动应用程序。然而,这很大程度上取决于你的应用是否是交互式的。

    我在上一个rubyday做了一个关于这种方法的演示。它是:http://www.slideshare.net/matteocollina/enter-the-app-era-with-ruby-on-rails-rubyday

    对于第三个选项,为了获得第二个选项的响应性,您可能希望像github那样尝试pajax。


    我在一个为期3个月的项目中投入了大约2个月的时间,该项目采用了您在这里概述的第二种方法。我们使用一个RESTfulAPI服务器端,前端是主干.js。js管理模板,jquery处理ajax和dom操作。对于旧的浏览器和搜索蜘蛛,我们已经回到服务器端渲染,但我们使用的HTML模板与使用MozillaRhino的车把前端相同。

    我们选择这种方法有很多不同的原因,但我们非常清楚,由于还没有大规模的证明,这有点冒险。尽管如此,到目前为止一切进展顺利。

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

    在选择这个基础设施时,让这两个项目完全独立是一个关键考虑因素。如果您正在寻找一个架构来混合不同的独立资源,而不需要任何依赖关系,那么这个方法值得一看。

    恐怕我不是红宝石人,所以我不能对其他方法发表评论。有时候冒险是可以的。其他时候,最好安全些。根据项目的类型,你会知道自己是怎样的。

    祝你在这里的选择好运。渴望看到别人也分享什么。


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

    我更喜欢Sinatra,只是将应用程序拆分为几个不同用途的机架式应用程序。我将制作一个特定于API的框架应用程序,它将涵盖我需要的API。然后可能是一个用户机架应用程序,将呈现我的网页。有时,如果需要,该版本会查询API,但通常只关注HTML站点本身。

    我不担心它,只要在需要的时候从用户端执行一个持久层查询。我不太关心建立一个完整的分离,因为他们通常会以不同的目的结束。

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

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


    对于atyorservice.com.cy,我们使用服务器端呈现的页面模板,尤其是覆盖SE部分的页面。以及在页面加载后使用API进行交互。因为我们的框架是MVC,所以所有控制器函数都复制到JSON输出和HTML输出。模板是干净的,只接收一个对象。这可以在几秒钟内转换为JS模板。我们总是维护服务器端模板,并根据需要重新转换为JS。


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

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

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

    是的,当然,为这个应用程序功能编写一个独立的JSONAPI。但不要太过分以至于编写一个JSONAPI来处理那些可以作为静态HTML文档工作的事情。


    REST服务器+JavaScript重客户端是我最近工作中遵循的原则。

    REST服务器是在node.js+express+mongodb(写的很好)、mongoose odm(建模数据很好,包括验证)、coffeescript(我现在改为es2015)中实现的,这对我来说很好。与其他可能的服务器端技术相比,node.js可能相对年轻,但它使我能够编写具有集成支付功能的可靠API。

    我使用了ember.js作为JavaScript框架,并且大多数应用程序逻辑都是在浏览器中执行的。我已经使用sass(scss)进行css预处理。

    ember是由强大社区支持的成熟框架。它是一个非常强大的框架,最近很多工作都集中在性能上,比如全新的微光渲染引擎(受到react的启发)。

    Ember核心团队正在开发FastBoot,它允许您在服务器端(特别是node.js)执行JavaScript Ember逻辑,并将应用程序的预渲染HTML(通常在浏览器中运行)发送给用户。这对SEO和用户体验很好,因为他不需要等待页面显示太久。

    ember-cli是一个很好的工具,可以帮助您组织代码,并且它在扩展代码库方面做得很好。灰烬也有它自己的插件生态系统,你可以从各种灰烬插件中选择。您可以轻松地抓取引导(在我的情况下)或基础,并将其添加到您的应用程序。

    不是为了通过Express提供所有服务,我选择使用nginx来提供图片和javascript重客户端。在我的案例中,使用nginx代理非常有用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    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: I love the separation of API & client. Smart people say this is
    the way to go. Great in theory. Seems cutting-edge and exciting.

    我可以说这在实践中也很好。分离RESTAPI的另一个优点是,您可以稍后将其重新用于其他应用程序。在完美的世界里,你不仅可以在网页上使用同样的RESTAPI,如果你决定写一个,也可以在移动应用程序上使用同样的RESTAPI。

    Con: Not much precedent. Not many examples of this done well. Public
    examples (twitter.com) feel sluggish & are even switching away from
    this approach.

    现在情况不同了。有很多例子可以使用RESTAPI+许多客户机。


    我决定使用选项2的架构来实现Infiniforms,因为它提供了一种将UI与业务逻辑分离的好方法。

    这样做的一个优点是API服务器可以独立于Web服务器进行扩展。如果您有多个客户机,那么网站将不需要扩展到与Web服务器相同的程度,因为有些客户机将是基于电话/平板电脑或桌面的。

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


    这是一个非常好的问题,我很惊讶,因为我认为这是一个非常常见的任务,这样我将有足够的资源来解决这个问题,但结果却不是真的。

    我的想法如下:-在不返回JSON或呈现HTML的情况下,创建一些在API控制器和HTML控制器之间具有公共逻辑的模块,并将此模块包含在HTML控制器和API控制器中,然后根据需要执行任何操作,例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    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


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

    很难预测API上的负载和流量模式,我们所看到的独立服务API的客户可以更轻松地进行配置和扩展。如果你必须这样做,那么就不那么容易了。另外,您的API使用可能会比您的Web客户机更快地扩展,然后您可以看到在哪里指导您的工作。

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


    我采用了一种混合方法,我们使用Sinatra作为基础,ActiveRecord/Postgres等服务于页面路由(瘦模板),公开Web应用程序可以使用的RESTAPI。在早期的开发中,诸如填充select选项之类的工作是通过帮助器渲染到slim模板中来完成的,但是在我们接近生产阶段时,随着我们开始更多地关注页面加载速度等,这将被换成对rest API的Ajax调用。

    很容易呈现在slim中的东西就是这样处理的,而这些东西(填充表单、从jquery接收表单发布数据、验证的submitHandler等)都是Ajax。

    测试是一个问题。现在,我在尝试将JSON数据传递到rack::test post测试时遇到了困难。


    在Rails中构建JSONAPI是第一类,JSONAPI::Resources gem为http://json api.org spec'd api做了大量工作。


    我个人更喜欢选择(3)作为解决方案。它被用在我以前的雇主拥有的几乎所有的网站上。这意味着你可以得到一些前端开发人员,他们知道所有关于javascript、浏览器怪癖以及什么不能为你的前端编码。他们只需要知道"curl xyz,你会得到一些json"就可以了。

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

    选项3为您提供了一个良好、可靠的三层体系结构。这意味着你从前端吐出的东西是SEO友好的,可以与旧的或新的浏览器(以及那些关闭了JS的浏览器)一起使用,如果你想的话,还可以使用JavaScript客户端模板(这样你可以用静态HTML处理旧的浏览器/GoogleBot,但是将JS构建的动态体验发送给使用最新版本的用户)Chrome浏览器或其他)。

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

    fwiw,$current_雇主可以在几个重要的地方使用选项3。我正在寻找一个好的Ruby框架来构建一些东西。我确信我可以把一堆gems粘合在一起,但是我更喜欢一个单一的产品,它广泛地提供了模板、"卷曲"、可选的身份验证、可选的memcache/nosql连接的缓存解决方案。在那里,我找不到任何连贯的东西:-(