arrays - 轨道 5+ API : single endpoint for both individual JSON object and array of JSON objects

标签 arrays json ruby-on-rails-5 rails-api

我正在构建一个使用 JSON 作为前端和后端之间格式的 Rails 5+ API。

我希望能够创建单个记录或多个记录,具体取决于是否发送了 JSON 对象数组。

请注意,我没有使用 JSON:API 规范,而是 JSON 对象作为根属性出现。

# Create a single child object for the associated parent
POST api/v1/parents/1/children PARAMS: { child_name: "Alpha" } 

# Create multiple children objects for the associated parent
POST api/v1/parents/1/children PARAMS: [{ child_name: "Alpha" }, { child_name: "Bravo" }]

在 Controller 中,我必须区分发送的是单个对象还是数组。如果设置了 Content-Type="application/json" header ,Rails 似乎会自动将 JSON 数据转换为 params["_json"] 键,我是使用它来判断是否传递了一个数组。

class ChildrenController < ApplicationController
  def create
    @parent = Parent.find(params[:parent_id])

    if params["_json"] && params["_json"].is_a?(Array)
      @children = []
      params["_json"].each do |child_attributes|
        @children << @parent.children.create!(child_attributes)
      end

      render json: @children
    else
      @child = @parent.children.create!(child_params)
      render json: @child
    end
  end

  def child_params
    params.permit(:child_name)
  end
end

问题

  1. 使用 params["_json"] 是否是判断数组是否已传递的标准方法?这看起来很老套,但我不确定是否有更好的方法。
  2. 如果传递了一个 JSON 对象数组,我如何仍然使用 StrongParameters child_params 方法?目前,如果用户传递一组 JSON 对象,他们可以放置他们想要的任何属性,我不会过滤掉它们。
  3. 是否有更好的方法来实现此功能?我不必为单个和多个创建都使用单个端点,我只是认为拥有一个可以处理单个或多个对象的 API 端点会更方便。
  4. 我还计划为 update 操作创建一个端点,该端点也可以接受单个或多个对象。这是一种不好的做法吗?

最佳答案

如果您将 JSON 数组(如 [{ child_name: "Alpha"}, { child_name: "Bravo"}])发送到端点,Rails 会将其存储到 _json 的参数散列。这样做的原因是,与单个 JSON 对象不同,如果不引入另一个键,就无法将数组提取到哈希中。

比方说,我们将 { child_name: "Alpha"} 发布到端点。参数将如下所示:

{"child_name"=>"Alpha", "format"=>:json, "controller"=>"api/children", "action"=>"create"}

现在,如果我们发布数组 [{ child_name: "Alpha"}, { child_name: "Bravo"}],它将被盲目提取到散列中,例如结果看起来像一个 JSON 对象:

{[{ child_name: "Alpha" }, { child_name: "Bravo" }], "format"=>:json, "controller"=>"api/children", "action"=>"create"}

不是有效的散列!所以 Rails 将您的 JSON 数组包装到 _json 中,它变成了:

{"_json" => [{ child_name: "Alpha" }, { child_name: "Bravo" }], "format"=>:json, "controller"=>"api/children", "action"=>"create"}

这发生了 here in the actionpack .是的,这似乎有点 hacky,但唯一且可能更清洁的解决方案是将请求正文中的所有数据包装到一个键中,如 data

那么对于您的实际问题:我如何在单个端点管理 JSON 对象和 JSON 数组?

你可以使用强大的参数,比如..

def children_params
  model_attributes = [:child_name]
  if params.key? '_json'
    params.permit(_json: model_attributes)['_json'] 
  else
    params.permit(*model_attributes)
  end
end

.. 并且在创建操作中看起来像..

def create
  result = Children.create!(children_params)
  if children_params.kind_of? Array
    @children = result
    render :index, status: :created
  else
    @child = result
    render :show, status: :created
  end
end

当然,您需要根据您的特定用例对其进行一些调整。从您的 API 的设计角度来看,我认为这样做是可以的。也许这应该在一个单独的问题中提出。

关于arrays - 轨道 5+ API : single endpoint for both individual JSON object and array of JSON objects,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52822103/

相关文章:

ruby-on-rails-5 - circleci 在 ruby​​ on rails 中的集成

ruby-on-rails - 无法在控制台 rails 中加载我的模型

python - 在 for 循环内删除 np 数组中的行

arrays - 将 Perl 数组放入哈希中

json - Angular orderBy 对象可能吗?

ios - 如何从登录中获取JSON数据?

javascript - 在 Ruby on Rails 中使用 API/客户端设置进行现场验证

php - 将数组从 android 发送到 php。 $_POST 显示 Array() 字符串

php - 比较两个数组并从 PHP 中的数组中删除数组

android - 如何使用 Map<String, Object> 或 List <object> 类在 Java 中反序列化嵌套的 Firebase 数据库?