{"action":"created","issue":{"url":"https://api.github.com/repos/maticzav/graphql-shield/issues/113","repository_url":"https://api.github.com/repos/maticzav/graphql-shield","labels_url":"https://api.github.com/repos/maticzav/graphql-shield/issues/113/labels{/name}","comments_url":"https://api.github.com/repos/maticzav/graphql-shield/issues/113/comments","events_url":"https://api.github.com/repos/maticzav/graphql-shield/issues/113/events","html_url":"https://github.com/maticzav/graphql-shield/issues/113","id":347096769,"node_id":"MDU6SXNzdWUzNDcwOTY3Njk=","number":113,"title":"Permissions on Input Types","user":{"login":"frankdugan3","id":10977914,"node_id":"MDQ6VXNlcjEwOTc3OTE0","avatar_url":"https://avatars3.githubusercontent.com/u/10977914?v=4","gravatar_id":"","url":"https://api.github.com/users/frankdugan3","html_url":"https://github.com/frankdugan3","followers_url":"https://api.github.com/users/frankdugan3/followers","following_url":"https://api.github.com/users/frankdugan3/following{/other_user}","gists_url":"https://api.github.com/users/frankdugan3/gists{/gist_id}","starred_url":"https://api.github.com/users/frankdugan3/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/frankdugan3/subscriptions","organizations_url":"https://api.github.com/users/frankdugan3/orgs","repos_url":"https://api.github.com/users/frankdugan3/repos","events_url":"https://api.github.com/users/frankdugan3/events{/privacy}","received_events_url":"https://api.github.com/users/frankdugan3/received_events","type":"User","site_admin":false},"labels":[{"id":834267978,"node_id":"MDU6TGFiZWw4MzQyNjc5Nzg=","url":"https://api.github.com/repos/maticzav/graphql-shield/labels/enhancement","name":"enhancement","color":"a2eeef","default":true}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":9,"created_at":"2018-08-02T17:01:07Z","updated_at":"2018-09-22T19:11:20Z","closed_at":null,"author_association":"NONE","body":"A use case I'm interested in is putting permissions on input types and individual fields of input types. This would simplify mutation permissions because you could use a generic mutation like `updateUser` but limit access to modifying certain fields of `User`.\r\n\r\nIs this supported or possible to add? I'd be happy to contribute if interested."},"comment":{"url":"https://api.github.com/repos/maticzav/graphql-shield/issues/comments/423766569","html_url":"https://github.com/maticzav/graphql-shield/issues/113#issuecomment-423766569","issue_url":"https://api.github.com/repos/maticzav/graphql-shield/issues/113","id":423766569,"node_id":"MDEyOklzc3VlQ29tbWVudDQyMzc2NjU2OQ==","user":{"login":"maticzav","id":3924224,"node_id":"MDQ6VXNlcjM5MjQyMjQ=","avatar_url":"https://avatars2.githubusercontent.com/u/3924224?v=4","gravatar_id":"","url":"https://api.github.com/users/maticzav","html_url":"https://github.com/maticzav","followers_url":"https://api.github.com/users/maticzav/followers","following_url":"https://api.github.com/users/maticzav/following{/other_user}","gists_url":"https://api.github.com/users/maticzav/gists{/gist_id}","starred_url":"https://api.github.com/users/maticzav/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/maticzav/subscriptions","organizations_url":"https://api.github.com/users/maticzav/orgs","repos_url":"https://api.github.com/users/maticzav/repos","events_url":"https://api.github.com/users/maticzav/events{/privacy}","received_events_url":"https://api.github.com/users/maticzav/received_events","type":"User","site_admin":false},"created_at":"2018-09-22T19:11:20Z","updated_at":"2018-09-22T19:11:20Z","author_association":"OWNER","body":"Hey 👋,\r\n\r\nI let this discussion evolve itself but I think we steered a bit out of the initial idea. Therefore, I would like to focus on tackling the overall problem that we are addressing not the implementation details themself.\r\n\r\nFirstly, I want to clarify what I understood as a proposal to `input` type scoped permissions. GraphQL allows the definition of so-called `input` types. Their primary focus is making more complex data structures accessible in arguments and not only in types themselves. An example of `input`-types usage would be a signup mutation, for example, which accepts multiple arguments. Because data can be nested or in any other way co-dependent, it makes sense to allow JSON-like input structures which we can test before execution (validation step).\r\n\r\nHence, this issue does not address how one should go about implementing scalar arguments validation but rather how we can make permissions on complex cross-field arguments reusable.\r\n\r\nTo corroborate the idea, let's examine the schema below. At first sight, we can notice we are creating a simple social network where one can create a single or even multiple events at the same time. There's a `GroupInput` input type that we use in two different places.\r\n\r\n\r\n```graphql\r\ntype Mutation {\r\n  createGroup(data: GroupInput): Group\r\n  createMultipleGroups(data: [GroupInput!]!): [Group!]!\r\n}\r\n\r\ninput GroupInput {\r\n  name: String!\r\n  members: [ID!]!\r\n}\r\n\r\ntype Group {\r\n  id: ID!\r\n  name: String!\r\n  members: [Member!]!\r\n}\r\n```\r\n\r\nFurthermore, groups require a unique name. Currently one would tackle such a problem by implementing the same code in two different places. To give a brief notion of how one could achieve this with the current `graphql-shield` features, let us examine the following code;\r\n\r\n```ts\r\nconst permissions = shield({\r\n  Mutation: {\r\n    createGroup: rule()(async (parent, { data }, ctx, info) => {\r\n      if (canGroupBeCreated(data)) {\r\n        return true\r\n      }\r\n      return false\r\n    }),\r\n    createMultipleGroups: rule()(async (parent, { data }, ctx, info) => {\r\n      if (data.every(group => canGroupBeCreated(group))) {\r\n        return true\r\n      }\r\n      return false\r\n    }),\r\n  },\r\n})\r\n```\r\n\r\nHorrible!\r\n\r\nNow, the idea of this issue is to find a way to make the above syntax far more appealing than the example we just witnessed. To give an idea of what seems the right direction, let's examine the last chunk of code on this particular topic;\r\n\r\n```ts\r\nconst permissions = shield({\r\n  InputTypes: {\r\n    GroupInput: {\r\n      name: val => isUniqueName(val)\r\n    }\r\n  },\r\n  Mutation: {\r\n    createGroup: rule()(async (parent, { data }, ctx, info) => {\r\n      // if (canGroupBeCreated(data)) {\r\n      //   return true\r\n      // }\r\n      // return false\r\n      //\r\n      // We already know that arguments passed - we can focus on other restrictions!\r\n    }),\r\n    createMultipleGroups: rule()(async (parent, { data }, ctx, info) => {\r\n      // if (data.every(group => canGroupBeCreated(group))) {\r\n      //   return true\r\n      // }\r\n      // return false\r\n      //\r\n      // We already know that arguments passed - we can focus on other restrictions!\r\n    }),\r\n  },\r\n})\r\n```\r\n\r\nI hope I made it a bit more clear of what I believe this proposal is aiming for. I hope we can find a genuinely concise and ingenious approach to tackling the problem as I think this could help, as can also be seen from the activeness of the discussion, many developers.\r\n\r\nI think I covered the first topic. 😄 \r\n\r\n---\r\n\r\nNow, the second topic I want to discuss is a response to a comment made by... it seems like it's not here anymore... anyways, I think this is a great place to share it! \r\n\r\n__With GraphQL you are always querying.__\r\n\r\nThere's been a numerous amount of questions addressing how one could foresee which fields the client is interested in and stop the execution of a query upfront if need be. This has been especially common in two particular scenarios; mutations and resolvers using `schemaDelagation`. I think this conceptual fatuity is a result of our approach to GraphQL - we are still thinking in REST.\r\n\r\nI believe `schemaDelegation` is quite often considered a somehow similar concept to REST-designed application. However, it is not! It's quite evident why people make this obvious mistake; delegation happens in one of the resolvers, and its result is forwarded to the resolver execution chain. Addressing the issue we can see why the relation seems complementary. Long story short, don't be fooled into thinking `schemaDelegation` is in any way similar to REST. It's not! Every value returned by the remote server is reprocessed once again locally.\r\n\r\nTo conclude, we often mingle REST with GraphQL when it comes to `schemaDelegation`. Nevertheless, they are not the same thing, far from it in fact. Thinking about \"foreseeing\" requested fields is, therefore, redundant - your logic shouldn't depend on the content of the processed query.\r\n\r\nFurthermore, as the quote above humbly suggests, we are always querying. There's no distinct difference between `Query` and `Mutation` - in fact, there's only one difference; one is processed serially and the other is processed asynchronously. The beauty of the graph is that one can compose a relational network and ideally access all fields from whichever vertex they desire. __Fields have to be independent.__\r\n\r\nSumming it all up, I believe a notion of \"foreseeing\" request content and relating function execution based on it is ridiculous. When we make internal changes as a result of arguments of `Query` or `Mutation` they shouldn't depend on the queried content.\r\n\r\nI hope this is somewhat helpful contribution to our discussion. I would love to hear your thoughts on it as well! 🙂 "}}
{"actor":{"display_login":"maticzav"}}