东亚银行、岚图汽车带你解锁 AIGC 时代的数字化人才培养各赛道新模式! 了解详情
写点什么

用 ROR 创建面向资源的服务

  • 2008-06-09
  • 本文字数:4170 字

    阅读完需:约 14 分钟

Ruby on Rails(ROR)的成功主要在于它的简单化假设(simplifying assumptions)。Rails 并不是向你提供一大堆用以解决各种问题的工具,而是为你提供了一种用以解决各类常见问题的方式。可以非常讯速地创建 Rails 应用,只要:尝试把关系数据库中的数据暴露出来,数据库表有确定的名称与结构,你愿意采用一种模型 - 视图 - 控制器(Model-View- Controller)架构,等等。因为在 Web 应用领域中,很多问题均符合这些假设,所以问题一般都能顺利解决,很少会遇到麻烦。

Rails 过去的版本暴露的是经典的 REST-RPC 混合服务,不过自 Rails 1.2 版起,它开始更加注重 REST 式设计了。或许这是必然的:HTTP 统一接口(uniform interface)是另一个简单化假设(simplifying assumptions)。我在第 7 章已经向你展示过 Rails 框架是如何做到用少量代码实现复杂的 REST 式服务了,在这一节,我将对此做一个回顾,并 概括性地讲述 Rails 的 REST 式架构。

路由

当 Rails 收到一个 HTTP 请求时,它会根据该请求的目标 URI,把请求路由给适当的控制器类(controller class)处理。如示例 12-1 所示,config/routes.rb 文件定义了 Rails 应如何对给定请求进行处理。

示例 12-1:一个简单的 routes.rb 文件

# routes.rb<p>ActionController::Routing::Routes.draw do |map|</p><p> map.resources :weblogs do |weblog|</p><p> weblog.resources :entries</p><p> end</p><p>end</p>config/routes.rb 文件可以相当复杂。第 7 章中展示的那个(见示例 7-3)相对来说算复杂的:我有很多资源,必须克服简单化假设,以得到想要的 URI 结构。示例 12-1 是一个较简单的、接纳了简单化假设的 routes.rb 文件。

通过该文件可知有两个控制器类(WeblogsController 和 EntriesController),该文件告诉 Rails 如何把收到的请 求路由给这两个类。WeblogsController 类处理发给 /weblogs 及 /weblogs/{id} 的请求。这里的路径变量{id}是放在 params[:id] 里的。

EntriesController 类处理发给 /weblogs/{weblog_id}/entries 及 /weblogs /{weblog_id}/entries/{id}的请求。这里的路径变量{weblog_id}是放在 params[:weblog_id] 里的, {id}是放在 params[:id] 里的。

{id}、{weblog_id}等变量常用于进行资源(resource)与系统里特定对象(object)的关联。它们常常跟数据库里的记录 ID 相对应,并经常被代入 ActiveRecord 的 find 方法。在我的社会性书签服务(见第 7 章)里,试过给它们像{username}这样具备描述 性的名称,并用它们来标识名称而不是 ID。

资源、控制器和视图

正如我在第 7 章中所讲述的那样,每个 Rails 控制器可以暴露两种资源。你可以有一个“列表”或“工厂”资源(响应 GET 和 / 或 POST 请求)和许 多“对象”资源(响应 GET、PUT 和 DELETE 请求)。一般来说,列表资源跟数据库表相对应,而对象资源跟数据库表里的记录相对应。

每个控制器都是一个 Ruby 类;于是,向一个类“发送”HTTP 请求,就意味着调用某个特定的方法。Rails 为每个控制器定义了五个标准方法,并 通过 HTTP GET 暴露了两个特殊的视图模板。在示例 12-1 中调用的 map.resources :weblogs 使得下面这七种 HTTP 请求成为可能。

  • GET/weblogs:一个博客列表。 Rails 调用 WeblogsController#indexmethod。
  • GET/weblogs/new:用于新建一个博客的表单。Rails 用 app/view/weblogs/new.rhtml 来呈现该视图。该视图是一个超媒体文件,它描述了客户端应发送什么样的 HTTP 请求来创建一个博客。
    换句话说,这是一个 HTML 表单(其实也可以是一个简短的 WADL 文档)。这个表单指出,客户端应向 /weblogs(见下)发送 POST 请求来新建博 客。它还指出客户端应为这个新博客采用什么样的表示格式(representation format),以便服务器能理解它。
  • POST/weblogs:创建一个新博客。Rails 调用 WeblogsController#create 方法。
  • GET/weblogs/{id}:一个博客。Rails 调用 WeblogsController#show 方法。
  • GET/weblogs/{id};edit:修改博客状态的表单。Rails 用 app/view/weblogs/edit.rhtml 来呈现该视图。该视图是一个超媒体文件,它描述了客户端应发送什么样的 HTTP 请求来修改博客的状态。
    该视图可以是一个 HTML 表单或一个简短的 WADL 文档。它告诉客户端应如何向 /weblogs/{id} 发送 PUT 请求。
  • PUT/weblogs/{id}:修改博客的状态。Rails 调用 WeblogsController#update 方法。在这里的“状态”指的是与博客资源关联的状态(state),如博客的名称及作者联系信息等。各篇博客文章是作为单独资源暴露出来的。
  • DELETE /weblogs/{id}:删除一个博客。Rails 调用 WeblogsController#delete 方法。

你也许不会为创建的所有控制器都暴露这七个接口。特别是,多半不会使用那些特殊视图,除非打算把 Web 服务作为一个 Web 网站来运营——没问题,你只要别实现那些不打算暴露的方法或视图就行了。

返回的表示

Rails 使我们能够更容易实现“根据客户端的请求,返回一个资源的不同表示”。示例 12-2 所示的 Ruby 代码可以返回一个博客的三种不同表示。 它将根据客户端请求的目标 URI 或 Accept 报头决定返回哪个表示。若客户端向 /weblogs/1.html 发出请求,就会得到 HTML 版表示;若客 户端向 /weblogs/1.png 发出请求,就会得到 PNG 版表示。respond_to 函数负责解释客户端的能力与需求。你所需要做的,就是按优先级 实现被支持的选项。

示例 12-2:返回多个表示中的一个

respond_to do |format|<p> format.html { render :template => 'weblogs/show' }</p><p> format.xml { render :xml => weblog.to_xml }</p><p> format.png { render :text => weblog.generate_image,</p><p> :content_type => "image/png" }</p><p>end</p><br></br>HTML 和 ActiveResource XML 序列化格式(serialization format)是两种特别常见的表示格式(representation formats)。HTML 表示是用 Rails 视图来展现的(就像在面向人类用户的 Web 应用程序中一样)。要把一个 ActiveRecord 对象暴露为 一个 XML 文档,你只要调用该对象(或对象列表)的 to_xml 方法即可。

通过 Rails 插件,我们可以轻易地把具有其他表示格式的数据暴露出来。在第 7 章,我安装了 atom-tools Ruby gem,用以为书签列表生成 Atom 提要(feed)。示例 7-8 里有一个 respond_to 代码块,它用于根据请求决定返回 Atom 还是普通 XML 表 示。

收到的表示

Rails 的工作就是根据收到的表示(incoming representation)生成一组关键字 - 值对(key-value pairs),并以 params hash 的形式来提供这些关键字 - 值对。默认情况下,它知道如何解析 Web 浏览器发送的表单编码的(form-encoded)文档,以及 to_xml 生 成的 XML 文档。

如果希望它能够解析自己的表示格式,你可以在 ActionController::Base.param_ parsers hash 里添加一个新的 Proc 对象。该 Proc 对象是一段代码,它的作用是处理服务器收到的具有给定媒体类型的表示。关于 param_parsers hash 的详细情况,请参阅 Rails 文档。

将 Web 应用作为 Web 服务

Rails 1.2 在融合 human web 与 programmable web 方面做得相当好。正如我在第 3 章中展示的,Rails 自带一个叫做 scaffold_resource 的代码生成器,它可以把数据库表暴露为一组资 源。你可以用 Web 浏览器来访问这些资源,也可以用 Web 服务客户端(如 ActiveResource)来访问这些资源。

如果你用 Web 浏览器来访问 scaffold_resource 服务的话,你会得到数据库对象的 HTML 表示,以及用于操作它们的 HTML 表单(由 前面提到的 new.rhtml 和 edit.rhtml 生成)。你可以通过发送表单编码格式(form-encoded format)的表示来创建、修改或删除资源。PUT 和 DELETE 请求是通过重载的 POST(overloaded POST)来模拟的。

如果你用一个 Web 服务客户端来访问 scaffold_resource 服务的话,你会得到数据库对象的 XML 表示。你可以修改该 XML 文档,并通过 PUT 请求把它发回去。非重载的(non-overloaded)POST 与 DELETE 请求的工作方式与你预期的一样。

关于 programmable web 与 human web 的基本相似性,没有比这更能令人信服的例子了。第 7 章因为篇幅原因所以没有讲述 Rails 的这方面内容,不过它非常有说服力地证明了 Rails 适合 于“设计具有相同功能的网站和 Web 服务”的场合。Rails 可以用同一套底层代码来暴露网站和 Web 服务。

Rails/ROA 设计步骤

下面是一个根据第 6 章的通用设计步骤修改后得到的版本。我在第 7 章设计社会性书签服务时已经非正式地采用这些设计步骤了。这里的设计步骤跟第 6 章的 区别在于:你不是直接把数据集划分为一个个资源,而是把数据集划分为一个个控制器,再把控制器划分为资源。这样,就不会出现“你最后得到的资源不适应 Rails 控制器”的问题了。

  1. 规划数据集。
  2. 把数据集分配给一个个控制器。
    对于每一个控制器:
  • 该控制器暴露的是一个列表或工厂资源吗?

  • 该控制器暴露的是一组对象资源吗?

  • 该控制器暴露的是一个用于创建或修改资源的表单资源吗?
    对于列表和对象资源:

    • 设计来自客户端的表示(假如与 Rails 标准不同的话)。
    • 设计返回给客户端的表示。
    • 把该资源与已有资源联系起来。
    • 考虑有哪些典型的事件经过?第 9 章描述的“基于数据库的应用的控制流”在此会有帮助。
    • 考虑可能出现哪些错误情况?同样,这里常常可以采用基于数据库的应用的控制流。

本文节选自博文视点出版公司即将推出的经典著作《RESTful Web Services 中文版》中的第 12 章《REST 式服务框架》。

《RESTful Web Services 中文版》向 读者介绍了什么是 REST、什么是面向资源的架构(Resource-Oriented Architecture,ROA)、REST 式设计的优点、REST 式 Web 服务的真实案例分析、如何用各种流行的编程语言编写 Web 服务客户端、如何 用三种流行的框架(Ruby on Rails、Restlet 和 Django)实现 REST 式服务等。不仅讲解 REST 与面向资源的架构(ROA)的概念与原理,还向读者介绍如何编写符合 REST 风格的 Web 2.0 应用。本书详实、易懂,实战性强,提供了大量 RESTful Web 服务开发的最佳实践和指导,适合广大的 Web 开发人员、Web 架构师及对 Web 开发或 Web 架构感兴趣的广大技术人员与学生阅读。

与此同时,博文视点还授权 InfoQ 中文站独家为大家提供额外的样章进行试读:欢迎下载第 3 章《REST 式服务有什么不同》

相关阅读:****

2008-06-09 20:322290
用户头像

发布了 63 篇内容, 共 25.1 次阅读, 收获喜欢 11 次。

关注

评论 1 条评论

发布
暂无评论
发现更多内容

不足10人的创业团队,怎么在半个月内上线一个新产品?

LigaAI

创业 敏捷开发管理 创业公司 远程开发 12 月 PK 榜

2022最新版SpringCloudAlibaba笔记,把微服务玩的出神入化

架构师之道

Java 微服务 架构师

TiDB 走进东软集团,共建医疗数字化基石

TiDB 社区干货传送门

通过TiOperator部署 TiDB

TiDB 社区干货传送门

实践案例 集群管理 管理与运维 扩/缩容 6.x 实践

跟我学Python图像处理丨带你入门OpenGL

华为云开发者联盟

Python 人工智能 华为云 12 月 PK 榜

纷繁复杂见真章,华为云产品需求管理利器CodeArts Req解读

华为云开发者联盟

云计算 需求管理 华为云 12 月 PK 榜

前端培训学习就业前景怎么样?

小谷哥

应用瓴羊Quick B,可以有效地提升企业的数据化分析能力

对不起该用户已成仙‖

“零代码”的瓴羊Quick BI即席分析,业务人员也能轻松上手

夏日星河

为什么很多产品经理,做不了产品管理?

LigaAI

产品经理 敏捷开发 产品管理 产品功能 12 月 PK 榜

武汉大数据培训机构怎么样

小谷哥

想学习大数据怎么选择培训机构

小谷哥

RTS超低延时直播技术:保障大型赛事直播零时差互动

阿里云视频云

云计算 阿里云 世界杯

CorelDRAW2023永久和谐版本下载安装教程

茶色酒

CorelDraw2023

文盘Rust -- r2d2 实现redis 连接池

TiDB 社区干货传送门

开发语言

专访|开源之夏最佳质量奖 Apache RocketMQ Committer 黄章衡

Apache RocketMQ

#开源 消息列队

SpringBoot内置tomcat启动过程及原理

京东科技开发者

tomcat 后端 tomcat源码解读 编程‘ spring-boot

cleanmymac2023免费绿色版下载安装教程

茶色酒

CleanMyMac2023

开发任务都完不成,哪有空搞稳定性?先看看这13条建议|TakinTalks论道

TakinTalks稳定性社区

技术管理

java程序员培训好就业吗

小谷哥

携手荣耀,出海正当时

荣耀开发者服务平台

开发者 App 出海 荣耀 honor

Web前端培训机构有哪些?

小谷哥

linux高可用小知识点汇总-行云管家

行云管家

高可用 ha 双机热备

TiDB Operator部署TiDB集群的监控与告警

TiDB 社区干货传送门

监控 实践案例 集群管理 管理与运维 扩/缩容

什么是IT资产?如何保障IT资产安全?

行云管家

网络安全 数据安全 IT资产

多样化功能助力企业精准决策,瓴羊Quick BI数据看板解析

对不起该用户已成仙‖

FL Studio正式推出全新21版首发新版DAW(数字音乐工作站)工具

茶色酒

FL STUDIO20.9 FL Studio 21 FL Studio21

TiDB集群安装TiDB Dashboard

TiDB 社区干货传送门

集群管理 管理与运维 故障排查/诊断

远程CG动画制作的神器:RayLink远程控制软件

RayLink远程工具

远程控制软件 远程办公软件 远控软件 远程桌面连接 RayLink

如何使用记事本编写 java 程序(从零开始学 Java 系列课程)

千锋IT教育

功能强大的国产API管理神器 Eolink,亲测好用

海拥(haiyong.site)

开发工具 API API测试

用ROR创建面向资源的服务_Ruby_徐涵_InfoQ精选文章