我要从头开始创建一堆网络应用程序。(详见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和客户端的分离。聪明的人说这是正确的选择。理论上很好。看起来很前卫,令人兴奋。
弊:没有太多先例。这方面做得好的例子不多。公开的例子(twitter.com)感觉很迟钝,甚至正在改变这种方法。
休息服务器+服务器端HTML客户端
制作一个JSON-only REST API服务器。做一个基本的HTML网站客户端,只访问REST API。更少的客户端JavaScript。
利:我喜欢API和客户端的分离。但是提供简单的HTML5是非常简单的,而且不是客户密集型的。
弊:没有太多先例。这方面做得好的例子不多。框架也不支持这一点。不知道该怎么处理。
尤其是从经验中寻求建议,而不仅仅是理论上的建议。
我更倾向于选择第二条和第三条。主要是因为第一条违反了关注点的分离,并且混合了各种各样的东西。最终,你会发现需要有一个没有匹配HTML页面的API端点/等等,你会在同一个代码库中遇到HTML和JSON端点混合的麻烦。它变得一团糟,即使它是MVP,你最终也不得不重写它,因为它太混乱了,甚至不值得挽救。
Going with #2 or #3 allows you to completely have a API that acts the same (for the most part) regardless. This provides great flexibility. I'm not 100% sold on Backbone/ember/whatever/etc.js just yet. I think its great, but as we're seeing with twitter this is not optimal. BUT... Twitter is also a huge beast of a company and has hundreds of millions of users. So any improvement can have a huge impact to bottom line on various areas of various business units. I think there is more to the decision than speed alone and they're not letting us in on that. But thats just my opinion. However, I do not discount backbone and its competitors. These apps are great to use and are very clean and are very responsive (for the most part).
第三种选择也有一定的吸引力。这就是我遵循帕累托原则(80/20规则)的地方,让20%的主标记(反之亦然)在服务器上呈现,然后让一个漂亮的JS客户端(backbone/etc)运行剩下的部分。你可能不会通过JS客户端与REST api进行100%的通信,但如果有必要的话,你会做一些工作来让suer体验更好。
我认为这是一个“视情况而定”的问题,答案是“这取决于”你在做什么,你在为谁服务,以及你希望他们得到什么样的体验。我认为你可以选择2个或3个或者它们的混合。
在Boundless,我们已经深入研究了第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页面上开放源代码,同时还有一篇博客文章解释如何使用它和更详细的整体架构。
更新:
With respect to people's concerns with Backbone, I think they are over-rated. Backbone is far more an organizational principle than it is a deep framework. Twitter's site itself is a giant beast of Javascript covering every corner-case across millions of users & legacy browsers, while loading tweets real-time, garbage collect, display lots of multimedia, etc. Of all the 'pure' js sites I've seen, Twitter is the odd one out. There have been many impressively complicated apps delivered via JS that fare very well.
体系结构的选择完全取决于您的目标。如果您正在寻找支持多个客户端的最快方式,并有机会接触到优秀的前端人才,那么投资一个独立的API是一个很好的方法。
我的3个月项目已经进行了2个月,采用了你在这里概述的第二种方法。我们使用一个RESTful API服务器端,前端是backbone.js。js管理模板,jQuery处理AJAX和DOM操作。对于旧的浏览器和搜索蜘蛛,我们已经退回到服务器端渲染,但是我们使用的是与使用Mozilla Rhino的Handlebars前端相同的HTML模板。
我们选择这种方法有很多不同的原因,但我们非常清楚,因为它还没有在大范围内得到证明,所以它有点冒险。尽管如此,到目前为止一切都进行得很顺利。。
到目前为止,我们一直在使用一个API,但在项目的下一个阶段,我们将使用第二个API。第一个用于大量数据,第二个更像一个通过API的CMS。
让项目的这两个部分彼此完全独立是选择这个基础设施的关键考虑因素。如果您正在寻找一种架构,可以在没有任何依赖的情况下混搭不同的独立资源,那么这种方法值得一试。
恐怕我不是Ruby的人,所以我不能评论其他方法。有时候冒险一下是可以的。其他时候最好谨慎行事。你会根据项目的类型来了解自己。
祝你选对了。也热衷于看别人分享什么。
我喜欢#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/其他语言代码。
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。
我们的项目Stack
我碰巧使用Python。我使用JsonRPC 2.0代替REST。我建议使用REST,尽管出于各种原因我喜欢JsonRPC的想法。我使用下面的库。考虑选项2/3的人可能会觉得有用。
一个快速的web微框架- Flask
前端服务器:Nginx
客户端MVC: Knockout.js
其他相关工具/库:
Jquery
js代表货币
Webshim:跨浏览器填充
director:客户端路由
生成HTML
我的结论和建议
选项3 !
总之,我已经成功地使用了选项2,但现在为了简单起见,我倾向于选项3。使用构建脚本生成静态HTML页面,并使用专门提供静态页面的超高速服务器提供这些页面是非常诱人的(选项2)。
我目前正致力于将一个巨大的CMS从选项1转换为选项3,并且进展顺利。我们选择在服务器端呈现标记,因为SEO对我们来说很重要,我们希望网站在移动电话上表现良好。
我使用node.js作为客户端的后端和一些模块来帮助我。我在这个过程中有点早期,但基础已经设置好了,这是一个检查数据确保它全部呈现正确的问题。这是我正在使用的:
Express for the app's foundation.
(https://github.com/visionmedia/express)
Request to fetch the data.
(https://github.com/mikeal/request)
Underscore templates that get rendered server side. I reuse these on the client.
(https://github.com/documentcloud/underscore)
UTML wraps underscore's templates to make them work with Express.
(https://github.com/mikefrey/utml)
Upfront collects templates and let's you chose which get sent to the client.
(https://github.com/mrDarcyMurphy/upfront)
Express Expose passes the fetched data, some modules, and templates to the front-end.
(https://github.com/visionmedia/express-expose)
Backbone creates models and views on the front-end after swallowing the data that got passed along.
(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)
虽然我正在寻找grunt (https//github.com/cowboy/grunt)
控制台跟踪(//github.com/LearnBoost/console-trace)。
不,我没有使用coffeescript。
这个选择对我来说非常有效。后端模型是不存在的,因为我们从API获得的数据结构良好,并且我将其逐字传递给前端。唯一的例外是我们的布局模型,我添加了一个属性,使渲染更智能和更轻。我没有使用任何花哨的模型库,只是一个函数,在初始化时添加我需要的东西并返回自己。
(抱歉奇怪的链接,我太n00b堆栈溢出让我张贴那么多)
在创建gauge .es时,我们选择了#2。我负责API (ruby, sinatra等),我的业务伙伴Steve Smith负责前端(javascript客户端)。
优点:
Move quickly in parallel. If I worked ahead of Steve, I could keep creating APIs for new features. If he worked ahead of me, he could fake out the API very easily and build the UI.
API for free. Having open access to the data in your app is quickly becoming a standard feature. If you start with an API from the ground up, you get this for free.
Clean separation. It is better to think of your app as an API with clients. Sure, the first and most important client may be a web one, but it sets you up for easily creating other clients (iPhone, Android).
缺点:
向后兼容性。这与API的关系比你直接的问题更大,但一旦你的API出来了,你就不能破坏它,也不能破坏所有的客户端。这并不意味着你要放慢速度,但它确实意味着你必须经常同时做两件事。添加到API或新字段是可以的,但是在没有版本控制的情况下不应该进行更改/删除。
我现在想不出什么骗局了。
结论:如果你计划发布一个API, API + JS客户端是正确的选择。
另外,我还建议在发布API之前完整地记录它。编写gage .es API的过程确实帮助了我们进行imp操作
http://get.gaug.es/documentation/api/
我个人更倾向于选择(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连接缓存解决方案的单一产品。这里我找不到任何有条理的东西:-(
REST服务器+ javascript为主的客户端是我在最近的工作中遵循的原则。
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(通常在浏览器中运行)给用户。这是伟大的搜索引擎优化和用户体验,因为他不会等待那么长时间的页面显示。
Ember 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;
}
}
利:我喜欢API和客户端的分离。聪明的人说这是
该走的路。理论上很好。看起来很前卫,令人兴奋。
我可以说它在实践中也很好。分离REST API的另一个优点是,以后可以在其他应用程序中重用它。在理想的情况下,你不仅可以在网页上使用相同的REST API,如果你决定编写一个移动应用程序,也可以在移动应用程序上使用。
弊:没有太多先例。这方面做得好的例子不多。公共
例子(twitter.com)感觉迟钝,甚至切换
这种方法。
现在情况看起来不一样了。有很多使用REST 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