Rails API设计

ESo*_*oft 11 design-patterns ruby-on-rails ruby-on-rails-3

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

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

Ile*_*ian 15

我使用了两种技术:在相同的控制器中编写API逻辑,并为API请求创建单独的控制器.

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

如果您有一个网站并且想要构建一个API,请单独进行.我和现有的控制器一起构建了一个,而且代码太乱了.我重复了几次代码,但我仍然不喜欢它(这也是个人品味的问题).

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

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

GET /api/v1/users.json
POST /api/v1/users.json
Run Code Online (Sandbox Code Playgroud)

然后,将来您可以创建另一个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 = ascicast

  • 到目前为止,我更喜欢这个答案 (2认同)

mač*_*ček 6

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

例如,如果您有此方法:

class UsersController < ApplicationController
  def index
    @users = User.all
  end
end
Run Code Online (Sandbox Code Playgroud)

您可以像这样添加JSON响应

class UsersController < Application Controller
  def index
    respond_to do |format|
      format.html
      format.js { render :json => @users }
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

现在,您有两个回复 /users

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

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

format.xml { render :xml => @users }
Run Code Online (Sandbox Code Playgroud)

现在您的应用将响应 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
Run Code Online (Sandbox Code Playgroud)

产生以下输出:

{ 
  "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" }
  ]
}
Run Code Online (Sandbox Code Playgroud)