5

我需要关于如何在 ruby​​ 中实现“客户端-服务器”网络应用程序的建议。任何指南和最佳实践都受到高度赞赏。我对 Ruby 方式和所需的 gem 感兴趣,因为它是一个理想的平台,以及实现这些东西的一般方式和逻辑。

遗憾的是,我不是一个优秀的 ruby​​ 程序员,也不是一个有多年经验的熟练系统设计师,所以我真的需要你的帮助,因为我仍然希望这件事最终会大放异彩。

应用程序的当前外观应该是这样的:

DB + Auth DB <-> API 应用程序 <-> 其他应用程序:

  • DB - 一个数据库或一组数据库,其中一个数据库用于一组用户(区域)。
  • Auth DB - 一个包含个人用户数据和登录信息的数据库,即使主数据库将在区域之间拆分,也可能是单个数据库。
  • API 应用程序——这个东西维护了所有关于数据、访问控制和翻译的逻辑,可能为所有应用程序提供一个翻译库。
  • 其他应用程序 - 一堆不同的应用程序,与 API 相关联,这可能是数据提供者,它们使用有关某些用户的一些数据和不同类型的 UI 来戳 API。所有应用程序都无法拥有自己的用户相关信息存储空间,并且只能通过 API 处理数据。

API App:看起来最好的工具是 Sinatra。问题是:

  1. 如何以清晰的方式组织 API?Rails 为模型和控制器提供了很好的 REST 路径设置和文件夹结构。有什么技巧可以提高 API 构建的经验吗?
  2. 如何维护访问权限?Warden 看起来不是一个好的选择,因为 API 客户端本身就是 Web 应用程序。所以我需要某种身份验证令牌。怎么可能做到?某种自定义 OAuth 提供程序?问题是,我不喜欢通过 API 存储和传递会话 cookie 的想法,每个请求都传递某种访问令牌。这也是

其他应用程序:主要是基于 Web 的 UI。这部分的逻辑选择是 Rails。主要问题是如何实现客户端身份验证检查。设计很酷,但是是否可以使其与令牌一起使用,还是更合适的工具?

4

1 回答 1

5

好的,这会有点长:

如果您已经熟悉 Rails,可以查看Rails API gem。该项目致力于从 Rails 中删除基于 JSON 的 RESTful API 不需要的额外内容。

这听起来可能很顺利,但它也有它的缺点。首先,您已经阅读了基本 Rails 功能所需的所有内容,您可能已经习惯了,例如respond_to. 这可能有点棘手,但是当您发现哪个 rails 模块最初提供了通常捆绑在 Rails 中的ActionController::Base.

话虽如此,让我举一个例子,说明我上周出于好奇为一个小型 API 项目做了什么:

初始情况

我们有一个主要完成的 Rails 应用程序。一切正常,但它基本上是单片的。一切都由 Rails 框架提供服务。对我们来说幸运的是,所有模型逻辑都捆绑在一个名为core. 该应用程序本质上允许登录的客户创建可通过最终用户视图搜索的产品。

目标是为此提供一个 RESTful API,它可以更有效地处理并发和更大的数据文件(即 CSV、XLS)。

介绍 Rails API

设计目标让我想到了 Rails API gem。基本安装的工作方式与 Rails 类似,只是调用了脚本rails-api,即:

rails-api new jsonapi

对我来说,这里的优势是我可以使用core来自其他应用程序的模型,但没有什么能阻止我将自己的模型引入jsonapi应用程序。

话虽如此,你可以做所有标准的 Rails 好东西,比如路由等。它遵循相同的约定。话又说回来,标准路由最初只对 JSON 做出反应,这有时会有点令人困惑。

让我举一个处理产品的 API Controller 的例子:

class ProductsController < ApplicationController
  include ActionController::HttpAuthentication::Token
  before_filter :find_product, :except => [:create, :index]

  def index
    render :json => @products
  end

  def create
    @product = product.new params[:product]

    if @product.save
      render :json => @product, :status => :created
    else
      render :json => @product.errors, :status => :unprocessable_entity
    end
  end

  def show
    render :json => @product
  end

  def update
    if @product.update_attributes params[:product]
      render :json => @product, :status => :ok
    else
      render :json => @product.errors
    end
  end

  def destroy
    if @product.destroy
      render :json => @product, :status => :ok
    else
      render :json => {:note => I18n.t("messages.deletion_impossible")}, :status => :unprocessable_entity
    end
  end

protected
  def find_product
    @product = Product.find params[:id]
  end
end

这没什么特别的。唯一需要注意的是ActionController::HttpAuthentication::Token明确包含的第二行。这是为了让您的 API 可以通过 HTTP 令牌得到保护。如果您想了解有关保护 API 的更多信息,我建议您阅读 Ryan Bates 的Railscasts 指南

本质上,您可以ApplicationController像这样提供一个前置过滤器:

class ApplicationController < ActionController::API  
  include ActionController::HttpAuthentication::Token::ControllerMethods
  [...]
  before_filter :restrict_access
  [...]
  def restrict_access
    authenticate_or_request_with_http_token do |token, options|
      # see if key is valid.
    end
  end
end

同样,请注意第二行,您必须ControllerMethods手动包含,否则没有控制器会知道authenticate_or_request_with_http_token.

延期

您可能知道基于 Rails 约定扩展 API。它的工作方式完全相同,只是默认情况下故意丢失了一些东西。如果您需要更多的 JSON 模板灵活性,我建议添加JBuilder ( Railscast )。

很好,但是客户呢?

就个人而言,当涉及到客户时,有很多选择。最终我发现它归结为你最喜欢什么。我个人可以在 Rails API 之上推荐一个小的node.js层,然后在它前面获得一个基于主干.js 的单页应用程序。如果你愿意,你也可以试试AngularJS 。您还可以围绕它构建另一个 Rails 应用程序,并从控制器操作中调用 API。

它还取决于您想要定位的平台 - 想到 iOS/Android 的本机应用程序。

我做出的选择是 node.js + 主干。它目前对我当时和该项目最有意义。节点层本质上持有与 API 通信所需的 Token,主干应用程序有一个小库来与节点层通信。然而,它可能是一把双刃剑,这取决于你的 API 有多复杂。对于一个小例子,这似乎很好,但是为了将主干应用程序的调用传递给 Rails API,可能会有很多代码重复。

验证

对于身份验证,您可以制作基于客户的 API 密钥(令牌),然后将控制器逻辑限制为仅接受该密钥允许的数据操作。您可以通过节点层管理会话。编辑:这是授权,而不是身份验证。没有什么能真正阻止您将 Authlogic 与 Rails API 一起使用——我还没有测试过它,但它应该可以工作。

我承认我还没有完成这部分 - 我希望其他人可以回答这个架构问题:-)

我希望我能提供一些见解。

PS:如果你想测试你的 API,我强烈推荐httpie(太棒了!)

于 2013-02-01T12:45:25.573 回答