Node object from interface implementation results in duplicate ID
woylie opened this issue · 2 comments
I defined an interface like this:
interface(:notification) do
field :id, non_null(:id)
# a bunch of other fields with resolver functions that resolve the same for every interface implementation
end
And there's a connection:
connection(node_type: :notification)
node object(:me) do
connection field :notifications, node_type: :notification do
resolve &Notification.list_my_notifications/2
end
end
And then I'm defining the concrete implementation as a node object like this. And since I don't want to copy all the fields including the resolver functions to every interface implementation, I'm using import_fields
to import them from the interface.
node object(:notification_about_something_specific) do
interface :notification
import_fields :notification
# plus specific fields for this notification type
end
And this basically works as expected when using the API. However, there is one problem: By using both node
and import_fields
, two :id
field definitions are created. And those two ID fields will end up in the SDL file generated with mix absinthe.schema.sdl
, which then causes tools that read that file to return an error.
I'm not sure how to fix this. I can move all the field definitions to the interface implementations instead of using import_fields
, but that kind of defeats the purpose of defining an interface. And I can remove the id
field from the interface definition, so that only the implementations define it, but that seems logically wrong.
I wonder if it would make sense if the node
macro overwrites any existing id
field instead of just adding one?
I've got the same error without explicit :id
field in the interface, just connection node
+ node object
with import_fields
is enough:
interface :revision do
field :version, non_null(:integer)
field :created_at, non_null(:datetime)
end
connection node_type: :revision
node object :user_revision do
interface :revision
import_fields :revision
field :role, non_null(:user_role)
end
Resulting SDL looks like:
interface Revision {
version: Int!
createdAt: DateTime!
}
interface Node {
"The id of the object."
id: ID!
}
type UserRevision implements Revision & Node {
"The id of the object."
id: ID!
"The ID of an object"
id: ID!
version: Int!
createdAt: DateTime!
role: UserRole!
}
type UserRevisionEdge {
cursor: String
node: UserRevision
}
type UserRevisionConnection {
pageInfo: PageInfo!
edges: [UserRevisionEdge]
}
Honestly, I didn't realize people were using import_fields
on interfaces. I can see how it is sometimes convenient but the moment you need a custom resolver things can get a bit weird. We can work to make import_fields
deduplicate, but there are trade offs. The duplicate ID thing without an explicit :id
field is weird, will look into it.