【问题标题】:Rails API designRails API 设计
【发布时间】:2012-12-11 07:30:06
【问题描述】:

我有一个主要基于 REST 的 Rails 站点,我想添加 JSON API 支持。

对于干净的代码库,我应该在现有控制器中添加此支持还是创建仅处理此 API 方法的新控制器,然后将所有通用代码移至模型/帮助程序?

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 design-patterns


    【解决方案1】:

    我使用了这两种技术:在同一个控制器中编写 API 逻辑,并为 API 请求制作单独的控制器。

    如果它只是一个 API,一个仅供您使用的小应用程序,请使用 rails 提供的默认控制器模型关系。代码会很干净。您的路线文件也将是干净的。

    如果您有一个网站,并且想要构建一个 API,请单独进行。我已经在现有控制器旁边构建了一个,代码太乱了。代码重构了好几次,还是不喜欢(这也是个人口味问题)。

    另一种解决方案是制作带有前缀的控制器。例如:ApiUsersController。这会使您的routes.rb 文件看起来很难看,因为您必须手动指定路由以匹配相应的控制器方法。

    对我来说可行的解决方案是将所有 API 逻辑移动到 API 命名空间下的单独控制器中。命名空间还允许您进行 API 版本控制。因此,例如,您的路线将是:

    GET /api/v1/users.json
    POST /api/v1/users.json
    

    然后,将来您可以创建另一个 API 版本,比如v2,而不会破坏使用旧版本 API 的现有应用程序。

    您可以在此处找到有关命名空间的更多信息:http://guides.rubyonrails.org/routing.html#controller-namespaces-and-routing

    关于带有版本控制的 REST-full API 的精彩教程:http://railscasts.com/episodes/350-rest-api-versioning?view=asciicast

    【讨论】:

    • 这是迄今为止我更喜欢的答案
    【解决方案2】:

    Rails 控制器生成器默认实现 JSON 响应。

    例如,如果你有这个方法:

    class UsersController < ApplicationController
      def index
        @users = User.all
      end
    end
    

    你可以像这样添加 JSON 响应

    class UsersController < Application Controller
      def index
        respond_to do |format|
          format.html
          format.js { render :json => @users }
        end
      end
    end
    

    现在,/users 有两个回复

    1. http://someapp.com/users
    2. http://someapp.com/users.json

    您可以很容易地添加另一个;例如,

    format.xml { render :xml => @users }
    

    现在您的应用将响应http://someapp.com/users.xml


    自定义你的 json

    您可能不想在 json 中输出表的所有字段。为此,请查看rails/jbuilder。它允许您使用构建器风格的 DSL 创建 JSON 结构。

    来自 jbuilder README 的示例

    Jbuilder.encode do |json|
      json.content format_content(@message.content)
      json.(@message, :created_at, :updated_at)
    
      json.author do
        json.name @message.creator.name.familiar
        json.email_address @message.creator.email_address_with_name
        json.url url_for(@message.creator, format: :json)
      end
    
      if current_user.admin?
        json.visitors calculate_visitors(@message)
      end
    
      json.comments @message.comments, :content, :created_at
    
      json.attachments @message.attachments do |attachment|
        json.filename attachment.filename
        json.url url_for(attachment)
      end
    end
    

    产生以下输出:

    { 
      "content": "<p>This is <i>serious</i> monkey business",
      "created_at": "2011-10-29T20:45:28-05:00",
      "updated_at": "2011-10-29T20:45:28-05:00",
    
      "author": {
        "name": "David H.",
        "email_address": "'David Heinemeier Hansson' <david@heinemeierhansson.com>",
        "url": "http://example.com/users/1-david.json"
      },
    
      "visitors": 15,
    
      "comments": [
        { "content": "Hello everyone!", "created_at": "2011-10-29T20:45:28-05:00" },
        { "content": "To you my good sir!", "created_at": "2011-10-29T20:47:28-05:00" }
      ],
    
      "attachments": [
        { "filename": "forecast.xls", "url": "http://example.com/downloads/forecast.xls" },
        { "filename": "presentation.pdf", "url": "http://example.com/downloads/presentation.pdf" }
      ]
    }
    

    【讨论】:

    • 有用但不能真正回答问题... Cristian Ilea 有一个最合适的。
    • format.js { render :json =&gt; @users }应该是format.json { render :json =&gt; @users }
    猜你喜欢
    • 2016-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-09
    • 2013-09-04
    • 2014-01-25
    • 2012-09-01
    • 2013-10-18
    相关资源
    最近更新 更多