Skip to content
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

Private fields #417

Closed
papigers opened this issue Jun 30, 2016 · 3 comments
Closed

Private fields #417

papigers opened this issue Jun 30, 2016 · 3 comments

Comments

@papigers
Copy link

I have an application with users which have many attributes, some of which are public, and some are private by default, and can become public if the user chooses to do so.

How can I handle the fetching of private attributes? I mean, I want that, for instance, if I'll try to fetch all the user's attributes, I'll get all his public attributes, and some null-ish value for his private attributes (not unauthorized error message).

I also want, to authorize each user to fetch/modify all of his data.

@stubailo
Copy link

Seems like this is something you could do in your model code:

// In your model
class Users {
  getPublicAttributes() {
    return _.pick(this.attrs, publicAttrs);
  }
}

// In your resolver to get the user
resolver(source, args, context) {
  const user = getUser(args.userId);
  if (context.user.isAllowedToSeePrivateAttributesOn(user)) {
    return user;
  } else {
    return user.getPublicAttributes();
  }
}

I don't think this is the job of the GraphQL API layer, since it's something that can be handled underneath. And if you need to, you can write some helpers to make this logic reusable in many resolvers/types/models.

@papigers
Copy link
Author

The thing's I'm missing is where the user attribute from the context came from? Where can I read more about context? How can I access it in relay?

I'm very new to GraphQL, obviously this isn't an issue, sorry.

@leebyron
Copy link
Contributor

GraphQL doesn't have a concept of private fields because GraphQL itself describes a public API. There's no need for a public API to describe what you can't access, instead it just doesn't describe it at all. Maybe there's a field called "passwordHash" that under no circumstance should be exposed over an API.

There's another concept which is permissions or access control. That is a field isn't necessarily "private" but that data is only visible to some users and not others. For example maybe your User has a field called "friends" which only the friends of that User can see. Or maybe you have a "isBanned" field that only admins of your app can see and everyone else gets null. These fields are still part of the public API but just have resolvers that conditionally return null.

For example:

// your model (pseudo-code, could just be the outcome of a DB fetch)
class User {
  getName() { ... } // public
  getIsBanned() { ... } // access controlled
  getPasswordHash() { ... } // private
}

// your GraphQL type
var UserType = new GraphQLObjectType({
  name: 'User',
  fields: {
    'name': {
      type: GraphQLString,
      resolve(model) { return model.getName(); }
    },
    'isBanned': {
      type: GraphQLBoolean,
      resolve(model, _, context) { 
        // assuming context contains info about who's logged in
        if (myIsAdminFunction(context)) { 
          return model.isBanned(); 
        }
      }
    },
    // note: passwordHash not exposed at all! It's private!
  }
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants