Skip to content

Instantly share code, notes, and snippets.

@eyston
Last active November 5, 2015 04:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eyston/ace33b385f57aabc7807 to your computer and use it in GitHub Desktop.
Save eyston/ace33b385f57aabc7807 to your computer and use it in GitHub Desktop.
const hasRole = (role, next) => {
return (obj, args, ctx) => {
if (ctx.rootValue.user.hasRole(role)) {
next(obj, args, ctx);
} else {
return null;
}
}
}
const { query, variables } = request.params; // from the request
const user = db.getUser(request.session.userId); // from your session -- pretend it has user id or something!
graphql(schema, query, {user}, variables); // shove the user in the root value
const UserType = new GraphQLObjectType({
name: 'User',
fields: {
email: {
type: GraphQLString,
resolve: (user, _, {rootValue}) => {
// only the current user can see their email
// can imagine this checking admin roles and stuff
if (user.id === rootValue.user.id) {
return user.email;
} else {
// maybe you can throw to add an error to the response!
return null;
}
}
},
socialSecurityNumber: {
type: GraphQLString,
resolve: hasRole('admin', user => user.socialSecurityNumber)
}
}
});
@eyston
Copy link
Author

eyston commented Nov 5, 2015

One last thing to remember: only scalar resolves are values that end up in the response.

Take the query:

query {
  user(id: 1) {
    name
  }
}

The resolve for user(id: 1) might query a database which returns {id: 1, name: "Erik", email: "eyston@gmail.com" }. This complex doesn't get copied to the response, it just gets handed to the next resolve function ... so your query response is currently:

{ "user": { } }

Then the resolve for name gets run. This resolve returns a value and since it is a scalar it gets added to the response:

{ "user": { "name": "Erik" } }

@eyston
Copy link
Author

eyston commented Nov 5, 2015

Yah, I've been tracking the om-next stuff. GraphQL is different in that it in fact is spec to walk the whole tree. This is actually what I wanted to get at in the last comment -- only the leave values matter. Every complex value which gets returned is simply the collection of its leaves.

With om-next the parser can return complex values meaning you do not necessarily walk the leaves. In this case your parser/read for :project would want to make sure the value it returns has been pre-filtered to the current user.

I haven't implemented a parser / done much with om-next but maybe the parser can be recursive? The Falcor router essentially does this. One route might handle :project and then defer to a different handler which handles :file or something.

@eyston
Copy link
Author

eyston commented Nov 5, 2015

@bostonou I can't stop:

https://www.youtube.com/watch?v=7lm3K8zVOdY

This was a talk from clojure/conj 2014 where a bank actually filters a datomic database to only include attributes a user can see. This means any query can be run safely as the only attribute values which can possibly be returned are authorized.

I have _zero_ idea if this is a good / bad idea, but definitely neato. And cognitect has included them in literature so maybe its a great idea, I dunno!

http://blog.cognitect.com/blog/2015/9/14/nubank

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment