-
Notifications
You must be signed in to change notification settings - Fork 822
Add support for custom global ID in v2 (Issue #1276) #1278
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for custom global ID in v2 (Issue #1276) #1278
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tcleonard thank you for the PR but I'm not sure I fully understand why this change is necessary? Why can't you created a custom Node
type to achieve the same result?
|
||
@classmethod | ||
def resolve_global_id(cls, info, global_id): | ||
_type = info.return_type.graphene_type._meta.name |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this will work if the return type is an interface or a union. I think it will return the interface/union type rather than the underling result type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you are probably correct... I will add a unit test for that and try to figure out a solution.
Let me know if you have an idea to suggest
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can't have a Union be a node so I don't think the union is really something we need to consider (unless I am missing your point), I'm looking into interfaces
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually same comment about interfaces... I don't really see why an interface would be a Node... it's the object type that you would derive from the interface that you would make a node field.
Did you have a specific case in mind? Cause I can't write a unit test that makes sense to test that...
You can't simply create a custom node without completely re-implementing everything because the type If you don't change the underlying graphene type (like in |
@tcleonard ok I see your point but I think this would be better solved by allowing you to specify what the def test_custom_id_field():
class CustomIntNode(Node):
class Meta:
name = "Node"
id_type = Int(required=True, description="The ID of the object")
@staticmethod
def to_global_id(type_, id):
return id
@staticmethod
def get_node_from_global_id(info, id, only_type=None):
return User(id=1, name="User 1",)
class User(ObjectType):
class Meta:
interfaces = [CustomIntNode]
name = String(description="The full name of the user")
class RootQuery(ObjectType):
node = CustomIntNode.Field(id_type=Int(required=True))
schema = Schema(query=RootQuery, types=[User])
assert str(schema) == dedent(
'''
schema {
query: RootQuery
}
type User implements Node {
"""The ID of the object"""
id: Int!
"""The full name of the user"""
name: String
}
interface Node {
"""The ID of the object"""
id: Int!
}
type RootQuery {
node(id: Int!): Node
}
'''
)
query = """
{
node(id: 1) {
id
}
}
"""
result = schema.execute(query)
assert not result.errors
assert result.data == {"node": {"id": 1}} ( Does that make sense? BTW there are some examples of creating a custom Node type here: https://github.com/graphql-python/graphene/blob/master/graphene/relay/tests/test_node_custom.py |
This is basically what I have done (as you can see in the unit test Why I did it that way is because, in the current implementation of graphene there is a strong assumption not only on the ID type but its content as well. Indeed, if I simply declare a custom node: class CustomIntNode(Node):
class Meta:
name = "Node"
id_type = Int(required=True, description="The ID of the object") It just doesn't work... because the implementation of the to/from global ID methods are also working on the assumption (implicitly) that your ID is of So that was the idea behind my approach to actually provide a way to offer this option but with the framework around it that tells you what you need to implement (so not just the id type but also the 2 methods needed to make that new ID type work) aka this interface: class BaseGlobalIDType:
"""
Base class that define the required attributes/method for a type.
"""
graphene_type = ID # type: Type[BaseType]
@classmethod
def resolve_global_id(cls, info, global_id):
# return _type, _id
raise NotImplementedError
@classmethod
def to_global_id(cls, _type, _id):
# return _id
raise NotImplementedError Because I find it quite disturbing to offer an option like you suggest that doesn't tell you that if you just use it as is... it does not work and you have to know somehow what else you need to do. Do you see my point? |
Hi @tcleonard @jkimbo this is a very interesting change, if we can use our IDs instead of Relays. |
Any update on this?... seeing how many questions are asked on stack overflow and in issues comments I am wondering if I could get some feedback. Happy to do some changes but at that point this PR is just going stale... |
@jkimbo is there any chance to get some feedback on that? or could you point it towards an active maintainer? |
Solution for issue #1276 for graphene v2