【发布时间】:2020-11-12 11:45:15
【问题描述】:
背景:
我有一个 Location 模型 has_one Address 和 has_many Rooms。当我想通过更新其name、address 或rooms 来更新位置时,我使用以下InputObjects 来执行此操作:
module Types
# Input interface for creating locations
class LocationUpdateType < Types::BaseInputObject
argument :id, ID, required: false
argument :name, String, required: true
argument :address, AddressUpdateType, required: true, as: :address_attributes
argument :rooms, [RoomUpdateType], required: true, as: :rooms_attributes
end
class AddressUpdateType < Types::BaseInputObject
argument :id, ID, required: true
# not sure if I need this or not but it's commented out for now
# argument :location_id, ID, required: true
argument :street, String, required: true
argument :city, String, required: true
argument :state, String, required: true
argument :zip_code, String, required: true
# I'm not using this yet but I'm anticipating it because
# accepts_nested_attributes can use it as an indicator to destroy this address
argument :_destroy, Boolean, required: false
end
class RoomUpdateType < Types::BaseInputObject
argument :id, ID, required: false
# same thing with this ID.
# argument :location_id, ID, required: true
argument :name, String, required: true
# accepts_nested_attributes flag for destroying related room records.
# like above, I'm not using it yet but I plan to.
argument :_destroy, Boolean, required: false
end
end
当我发出 GraphQL 请求时,我的日志中出现以下信息:
Processing by GraphqlController#execute as JSON
Variables: {"input"=>
{"id"=>"TG9jYXRpb24tMzM=",
"location"=>
{"name"=>"A New Building",
"address"=>
{"city"=>"Anytown",
"id"=>"QWRkcmVzcy0zMw==",
"state"=>"CA",
"street"=>"444 New Rd Suite 4",
"zipCode"=>"93400"},
"rooms"=>[{"id"=>"Um9vbS00Mw==", "name"=>"New Room"}]}}}
mutation locationUpdate($input:LocationUpdateInput!) {
locationUpdate(input: $input) {
errors
location {
id
name
address {
city
id
state
street
zipCode
}
rooms {
id
name
}
}
}
}
这是有道理的,我不想在客户端上使用真正的IDs,而是使用经过混淆的中继节点 ID。
问题:
当我的请求得到解决时,我正在使用这个 Mutation:
module Mutations
# Update a Location, its address and rooms.
class LocationUpdate < AdminMutation
null true
description 'Updates a locations for an account'
field :location, Types::LocationType, null: true
field :errors, [String], null: true
argument :id, ID, required: true
argument :location, Types::LocationUpdateType, required: true
def resolve(id:, location:)
begin
l = ApptSchema.object_from_id(id)
rescue StandardError
l = nil
end
return { location: nil, errors: ['Location not found'] } if l.blank?
print location.to_h
# return { location: nil }
# This is throwing an error because it doesn't like the Relay Node IDs.
l.update(location.to_h)
return { location: nil, errors: l.errors.full_messages } unless l.valid?
{ location: l }
end
end
end
当我打印传递到此解析器的哈希时,我得到以下信息:
{
:name=>"A New Building",
:address_attributes=>{
:id=>"QWRkcmVzcy0zMw==",
:street=>"444 New Rd Suite 4",
:city=>"Anytown",
:state=>"CA",
:zip_code=>"93400"
},
:rooms_attributes=>[{:id=>"Um9vbS00Mw==", :name=>"New Room"}]
}
l.update 运行时,出现以下错误:
Couldn't find Room with ID=Um9vbS00Mw== for Location with ID=33
这对我来说非常有意义,因为中继节点 ID 没有存储在数据库中,所以我想我想弄清楚如何将 room.id 从中继节点 ID 转换为数据库中的 ID .
现在,我可以挖掘哈希并使用 ApptSchema.object_from_id 并将所有中继节点 ID 转换为 Rails ID,但这需要对每个节点进行数据库访问。我看到Connections 的文档列出了here,但这看起来更像是如何处理查询和分页。
如果我打算用相关记录更新记录,是否需要将数据库 ID 发送给客户?这不会违背中继节点 ID 的目的吗?有没有办法配置我的输入对象类型以将中继节点 ID 转换为 Rails ID,以便我在发送到解析器的哈希中获得正确的 ID?
【问题讨论】:
-
对relay不是很熟悉,但是好像需要缓存relay节点id?通过为它们提供查找(redis?)或将中继节点ID存储在rails模型中?基本上要花费高昂的前期成本来进行转换,因此您以后不需要这样做。如果不是,为什么这是不可能的,可能会为其他解决方案提供一些见解。
-
如果你不熟悉 Relay,我猜你可能也不熟悉 GraphQL?如果您是,那么我可以告诉您:我可以将带有模型类型的数据库 ID 作为 JSON 响应传递,然后在执行 GQL 请求时将其发回。我只是认为这违背了使用 Relay 的目的,因为有人可以使用调试器访问该数据库 ID,这将使他们能够深入了解数据库中的其他数据。我不认为将中继 ID 存储在数据库中是解决此问题的正确方法,但我可能在这里错误地使用了 GraphQL。
-
其实对 GraphQL 有点熟悉,所以我没有提到它,只是没有使用 Relay。再次快速检查显示 Relay 用于 React。在这种情况下,我的建议更简单。切勿将实际 ID 传递给客户端。看看
friendly_idgem。虽然这可能会解决一个不同的问题。不清楚您试图防止泄漏的确切见解,如果它是顺序排序(IE:给定 ID 5000,ID 1-4999 可能有效)然后使用友好 id 和SecureRandom.alphanumeric(24)创建 slug 是一个相当标准的解决方案以防止这种情况发生。 -
请注意,
SecureRandom.alphanumeric(24)的随机性大约等于 UUID(和更清洁)的随机性,这就是我提到它的原因。 -
Relay 和 GQL 标准是由 Facebook 创建的(我相信),因此您可以将它与 React.js+Relay 客户端解决方案一起使用,但 Relay 和 GQL 一样是一个标准。你可以跟随或不跟随,这取决于你。 Relay 支持
clientMutationId,它可以通过请求传递,并与响应一起返回。我在我的项目中不支持这一点,但它是一个 Relay 支架,所以我猜你可以在后端支持 Node.js 上的 Relay,或者在前端使用 Angular。不过,我会考虑研究这两种解决方案,谢谢。
标签: ruby-on-rails ruby graphql relay