0

Lets say I got a user Type

class UserType(DjangoObjectType):
    class Meta:
        model = User
        fields = [
            "fieldA",
            "fieldB",
            "relationshipA",
            "relationshipB"
        ]

And I want fieldB and relationshipB to be visible only to the owner (user).
What is the best strategy to do this?
Initially Ive created a PublicUserType excluding private fields, but quickly I realized that it might not be scalable because not only I'll have to create private representation for UserType I'll might also create private representation for any relationship (relationshipA etc), and proper resolvers, and duplicate fragments etc.
Is there a best practice here?

ItayAmza
  • 819
  • 9
  • 21
  • Take a look at this example: https://docs.graphene-python.org/projects/django/en/latest/queries/#default-queryset – JoVi Jul 28 '23 at 15:08
  • But how can it help with hiding specific fields? – ItayAmza Jul 28 '23 at 15:25
  • 1
    You can filter in the `queryset` or using a field resolver (for example: `resolve_fieldB(self, info)` to return `None` if `fieldB` must be hidden. Keep in mind that different from APIs, you will need a GQL query specifing the fields you want to query. If you have sure that a public user will not query the "private" fields, You can raise an `GraphQLError("Entity not found")`. – JoVi Jul 28 '23 at 15:44
  • I think that overriding resolvers might be better suited for my needs, thanks. – ItayAmza Jul 29 '23 at 18:03
  • Does this answer your question? [How to limit field access on a model based on user type on Graphene/Django?](https://stackoverflow.com/questions/49084322/how-to-limit-field-access-on-a-model-based-on-user-type-on-graphene-django) – Ahtisham Aug 01 '23 at 15:37
  • Yes, that's pretty close to what we discussed above, thanks @Ahtisham, I will also create permissions decorator to prevent boilerplate code. – ItayAmza Aug 03 '23 at 17:06

1 Answers1

0

My solution is:
Create decorators.py file

from functools import wraps
from graphql import GraphQLError
from api.utils import snake_to_camel_case

def private_field(func):
    @wraps(func)
    def wrapper(self, info):
        user = info.context.user

        if user.id != self.id:
            field_name = func.__name__.replace('resolve_', '')
            field_name_camel_cased = snake_to_camel_case(field_name)
            raise GraphQLError(f'You do not have permissions to access {field_name}')
        
        return func(self, info)
    return wrapper

snake_to_camel_case func:

def snake_to_camel_case(string):
    components = string.split('_')
    return components[0] + ''.join(x.title() for x in components[1:])

and finally on my schema file resolver:

@private_field
    def resolve_private_field(self, info):
        return self.private_field

Response should look something like that:

{
    "errors": [
        {
            "message": "You do not have permissions to access privateField",
...

Now obviously this solution is super specific for my needs atm but it should be easy enough to make it more generic and scalable for any scenario.

ItayAmza
  • 819
  • 9
  • 21