{"action":"created","comment":{"url":"https://api.github.com/repos/apollographql/graphql-tools/pulls/comments/171031075","pull_request_review_id":99811568,"id":171031075,"diff_hunk":"@@ -1,179 +1,527 @@\n ---\n title: Schema directives\n-description: Using custom Directive on FIELD_DEFINITION\n+description: Implementing and using custom `@directive`s that transform schema types, fields, and arguments\n ---\n \n-## Simple Directive example\n+## Schema directives\n \n-Let's take a look at how we can create `@upper` Directive to upper-case a string returned from resolve on Field\n-[See a complete runnable example on Launchpad.](https://launchpad.graphql.com/p00rw37qx0)\n+A _directive_ is an identifier preceded by a `@` character, optionally followed by a list of named arguments, which can appear after almost any form of syntax in the GraphQL query or schema languages.\n \n-To start, let's grab the schema definition string from the `makeExecutableSchema` example [in the \"Generating a schema\" article](/tools/graphql-tools/generate-schema.html#example).\n+The [GraphQL specification](http://facebook.github.io/graphql/October2016/#sec-Type-System.Directives) requires every server implementation to support at least two directives, `@skip(if: Boolean)` and `@include(if: Boolean)`, which can be used during query execution to conditionally omit or include certain fields. The [GraphQL.js reference implementation](https://github.com/graphql/graphql-js) provides one additional built-in [`@deprecated`](https://github.com/graphql/graphql-js/blob/master/src/type/directives.js) directive, which is useful for indicating that a field or `enum` value should no longer be used.\n \n-```js\n-import { makeExecutableSchema } from 'graphql-tools';\n-import { graphql } from 'graphql';\n+However, the formal syntax of the GraphQL query and schema languages allows arbitrary user-defined `@directive`s to appear as modifiers following almost any kind of type, field, or argument. Unless the server ascribes special meaning to these annotations, they are typically ignored after parsing, almost as if they were comments. But if the server knows how to interpret them, `@directive` annotations can be a powerful tool for preventing repetition, specifying extra behavior, enforcing additional type or value restrictions, and enabling static analysis.\n+\n+This document focuses on `@directive`s that appear in GraphQL _schemas_ written in Schema Definition Language (SDL), as described in the [Schemas and Types](http://graphql.org/learn/schema/) section of the GraphQL.org documentation. These `@directive`s can be used to modify the structure and behavior of a GraphQL schema in ways that would not be possible using SDL syntax alone.","path":"docs/source/schema-directives.md","position":22,"original_position":22,"commit_id":"21d6479016d30a72bdb3974114b29ad92f3d49e2","original_commit_id":"21d6479016d30a72bdb3974114b29ad92f3d49e2","user":{"login":"stubailo","id":448783,"avatar_url":"https://avatars3.githubusercontent.com/u/448783?v=4","gravatar_id":"","url":"https://api.github.com/users/stubailo","html_url":"https://github.com/stubailo","followers_url":"https://api.github.com/users/stubailo/followers","following_url":"https://api.github.com/users/stubailo/following{/other_user}","gists_url":"https://api.github.com/users/stubailo/gists{/gist_id}","starred_url":"https://api.github.com/users/stubailo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stubailo/subscriptions","organizations_url":"https://api.github.com/users/stubailo/orgs","repos_url":"https://api.github.com/users/stubailo/repos","events_url":"https://api.github.com/users/stubailo/events{/privacy}","received_events_url":"https://api.github.com/users/stubailo/received_events","type":"User","site_admin":false},"body":"I think we should basically just start here.","created_at":"2018-02-27T19:02:35Z","updated_at":"2018-02-27T19:09:14Z","html_url":"https://github.com/apollographql/graphql-tools/pull/640#discussion_r171031075","pull_request_url":"https://api.github.com/repos/apollographql/graphql-tools/pulls/640","author_association":"OWNER","_links":{"self":{"href":"https://api.github.com/repos/apollographql/graphql-tools/pulls/comments/171031075"},"html":{"href":"https://github.com/apollographql/graphql-tools/pull/640#discussion_r171031075"},"pull_request":{"href":"https://api.github.com/repos/apollographql/graphql-tools/pulls/640"}}},"pull_request":{"url":"https://api.github.com/repos/apollographql/graphql-tools/pulls/640","id":169670923,"html_url":"https://github.com/apollographql/graphql-tools/pull/640","diff_url":"https://github.com/apollographql/graphql-tools/pull/640.diff","patch_url":"https://github.com/apollographql/graphql-tools/pull/640.patch","issue_url":"https://api.github.com/repos/apollographql/graphql-tools/issues/640","number":640,"state":"open","locked":false,"title":"Abstraction for reusable schema @directive implementations.","user":{"login":"benjamn","id":5750,"avatar_url":"https://avatars0.githubusercontent.com/u/5750?v=4","gravatar_id":"","url":"https://api.github.com/users/benjamn","html_url":"https://github.com/benjamn","followers_url":"https://api.github.com/users/benjamn/followers","following_url":"https://api.github.com/users/benjamn/following{/other_user}","gists_url":"https://api.github.com/users/benjamn/gists{/gist_id}","starred_url":"https://api.github.com/users/benjamn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/benjamn/subscriptions","organizations_url":"https://api.github.com/users/benjamn/orgs","repos_url":"https://api.github.com/users/benjamn/repos","events_url":"https://api.github.com/users/benjamn/events{/privacy}","received_events_url":"https://api.github.com/users/benjamn/received_events","type":"User","site_admin":false},"body":"This PR implements a class called `SchemaDirectiveVisitor` that enables writing reusable implementations of any `@directives` that appear in a GraphQL schema written in [Schema Definition Language](http://graphql.org/learn/schema/#type-language).\r\n\r\n> Note: I would *not* recommend reviewing this PR commit-by-commit. Instead, just have a look at the combined changes, which are amply commented. There were a lot of detours as I figured out exactly which abstractions I needed.\r\n\r\nBy overriding one or more `visit{Object,Union,...}` methods, a subclass of `SchemaDirectiveVisitor` registers interest in certain schema types, such as `GraphQLObjectType`, `GraphQLUnionType`, etc. When `SchemaDirectiveVisitor.visitSchemaDirectives` is called with a `GraphQLSchema` object and a map of visitor subclasses, the overridden visitor methods of those subclasses are able to obtain references to any schema type objects that have `@directive`s attached to them, enabling the visitors to inspect or modify the schema as appropriate.\r\n\r\nFor example, if a directive called `@rest(url: \"...\")` appears after a field definition, a `SchemaDirectiveVisitor` subclass could provide meaning to that directive by overriding the `visitFieldDefinition` method (which receives a `GraphQLField` parameter), and then the body of that visitor method could manipulate the field's resolver function to fetch data from a REST endpoint:\r\n\r\n```js\r\nconst typeDefs = `\r\ntype Query {\r\n  people: [Person] @rest(url: \"/api/v1/people\")\r\n}`;\r\n\r\nconst schema = makeExecutableSchema({ typeDefs });\r\n\r\nSchemaDirectiveVisitor.visitSchemaDirectives(schema, {\r\n  rest: class extends SchemaDirectiveVisitor {\r\n    public visitFieldDefinition(field: GraphQLField<any, any>) {\r\n      const { url } = this.args;\r\n      field.resolve = () => fetch(url);\r\n    }\r\n  }\r\n});\r\n```\r\n\r\nThe subclass in this example is defined as an anonymous `class` expression, for brevity. A truly reusable `SchemaDirectiveVisitor` would most likely be defined in a library using a named class declaration, and then exported for consumption by other modules and packages.\r\n\r\nSee my comments in the code below for more explanation of how this all works.\r\n\r\n### Next steps:\r\n\r\n- [x] Update the [schema directive docs](https://www.apollographql.com/docs/graphql-tools/schema-directives.html) to describe this new abstraction (not just `directiveResolvers`).\r\n- [ ] Comment on issues in this repo related to schema directives.\r\n- [ ] Add more examples of specific use cases to the tests, e.g. https://github.com/apollographql/graphql-tools/issues/638#issuecomment-366303740.\r\n- [x] Work with @freiksenet to align our schema-wrangling efforts.\r\n- [ ] Write a blog post about this functionality.\r\n","created_at":"2018-02-16T16:41:01Z","updated_at":"2018-02-27T19:09:14Z","closed_at":null,"merged_at":null,"merge_commit_sha":"9785db807232823e5cf45f8bb03f7d27c675f687","assignee":{"login":"benjamn","id":5750,"avatar_url":"https://avatars0.githubusercontent.com/u/5750?v=4","gravatar_id":"","url":"https://api.github.com/users/benjamn","html_url":"https://github.com/benjamn","followers_url":"https://api.github.com/users/benjamn/followers","following_url":"https://api.github.com/users/benjamn/following{/other_user}","gists_url":"https://api.github.com/users/benjamn/gists{/gist_id}","starred_url":"https://api.github.com/users/benjamn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/benjamn/subscriptions","organizations_url":"https://api.github.com/users/benjamn/orgs","repos_url":"https://api.github.com/users/benjamn/repos","events_url":"https://api.github.com/users/benjamn/events{/privacy}","received_events_url":"https://api.github.com/users/benjamn/received_events","type":"User","site_admin":false},"assignees":[{"login":"benjamn","id":5750,"avatar_url":"https://avatars0.githubusercontent.com/u/5750?v=4","gravatar_id":"","url":"https://api.github.com/users/benjamn","html_url":"https://github.com/benjamn","followers_url":"https://api.github.com/users/benjamn/followers","following_url":"https://api.github.com/users/benjamn/following{/other_user}","gists_url":"https://api.github.com/users/benjamn/gists{/gist_id}","starred_url":"https://api.github.com/users/benjamn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/benjamn/subscriptions","organizations_url":"https://api.github.com/users/benjamn/orgs","repos_url":"https://api.github.com/users/benjamn/repos","events_url":"https://api.github.com/users/benjamn/events{/privacy}","received_events_url":"https://api.github.com/users/benjamn/received_events","type":"User","site_admin":false}],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/apollographql/graphql-tools/pulls/640/commits","review_comments_url":"https://api.github.com/repos/apollographql/graphql-tools/pulls/640/comments","review_comment_url":"https://api.github.com/repos/apollographql/graphql-tools/pulls/comments{/number}","comments_url":"https://api.github.com/repos/apollographql/graphql-tools/issues/640/comments","statuses_url":"https://api.github.com/repos/apollographql/graphql-tools/statuses/21d6479016d30a72bdb3974114b29ad92f3d49e2","head":{"label":"apollographql:wip-schema-directives","ref":"wip-schema-directives","sha":"21d6479016d30a72bdb3974114b29ad92f3d49e2","user":{"login":"apollographql","id":17189275,"avatar_url":"https://avatars0.githubusercontent.com/u/17189275?v=4","gravatar_id":"","url":"https://api.github.com/users/apollographql","html_url":"https://github.com/apollographql","followers_url":"https://api.github.com/users/apollographql/followers","following_url":"https://api.github.com/users/apollographql/following{/other_user}","gists_url":"https://api.github.com/users/apollographql/gists{/gist_id}","starred_url":"https://api.github.com/users/apollographql/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apollographql/subscriptions","organizations_url":"https://api.github.com/users/apollographql/orgs","repos_url":"https://api.github.com/users/apollographql/repos","events_url":"https://api.github.com/users/apollographql/events{/privacy}","received_events_url":"https://api.github.com/users/apollographql/received_events","type":"Organization","site_admin":false},"repo":{"id":54432168,"name":"graphql-tools","full_name":"apollographql/graphql-tools","owner":{"login":"apollographql","id":17189275,"avatar_url":"https://avatars0.githubusercontent.com/u/17189275?v=4","gravatar_id":"","url":"https://api.github.com/users/apollographql","html_url":"https://github.com/apollographql","followers_url":"https://api.github.com/users/apollographql/followers","following_url":"https://api.github.com/users/apollographql/following{/other_user}","gists_url":"https://api.github.com/users/apollographql/gists{/gist_id}","starred_url":"https://api.github.com/users/apollographql/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apollographql/subscriptions","organizations_url":"https://api.github.com/users/apollographql/orgs","repos_url":"https://api.github.com/users/apollographql/repos","events_url":"https://api.github.com/users/apollographql/events{/privacy}","received_events_url":"https://api.github.com/users/apollographql/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/apollographql/graphql-tools","description":":wrench: Build, mock, and stitch a GraphQL schema using the schema language","fork":false,"url":"https://api.github.com/repos/apollographql/graphql-tools","forks_url":"https://api.github.com/repos/apollographql/graphql-tools/forks","keys_url":"https://api.github.com/repos/apollographql/graphql-tools/keys{/key_id}","collaborators_url":"https://api.github.com/repos/apollographql/graphql-tools/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/apollographql/graphql-tools/teams","hooks_url":"https://api.github.com/repos/apollographql/graphql-tools/hooks","issue_events_url":"https://api.github.com/repos/apollographql/graphql-tools/issues/events{/number}","events_url":"https://api.github.com/repos/apollographql/graphql-tools/events","assignees_url":"https://api.github.com/repos/apollographql/graphql-tools/assignees{/user}","branches_url":"https://api.github.com/repos/apollographql/graphql-tools/branches{/branch}","tags_url":"https://api.github.com/repos/apollographql/graphql-tools/tags","blobs_url":"https://api.github.com/repos/apollographql/graphql-tools/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/apollographql/graphql-tools/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/apollographql/graphql-tools/git/refs{/sha}","trees_url":"https://api.github.com/repos/apollographql/graphql-tools/git/trees{/sha}","statuses_url":"https://api.github.com/repos/apollographql/graphql-tools/statuses/{sha}","languages_url":"https://api.github.com/repos/apollographql/graphql-tools/languages","stargazers_url":"https://api.github.com/repos/apollographql/graphql-tools/stargazers","contributors_url":"https://api.github.com/repos/apollographql/graphql-tools/contributors","subscribers_url":"https://api.github.com/repos/apollographql/graphql-tools/subscribers","subscription_url":"https://api.github.com/repos/apollographql/graphql-tools/subscription","commits_url":"https://api.github.com/repos/apollographql/graphql-tools/commits{/sha}","git_commits_url":"https://api.github.com/repos/apollographql/graphql-tools/git/commits{/sha}","comments_url":"https://api.github.com/repos/apollographql/graphql-tools/comments{/number}","issue_comment_url":"https://api.github.com/repos/apollographql/graphql-tools/issues/comments{/number}","contents_url":"https://api.github.com/repos/apollographql/graphql-tools/contents/{+path}","compare_url":"https://api.github.com/repos/apollographql/graphql-tools/compare/{base}...{head}","merges_url":"https://api.github.com/repos/apollographql/graphql-tools/merges","archive_url":"https://api.github.com/repos/apollographql/graphql-tools/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/apollographql/graphql-tools/downloads","issues_url":"https://api.github.com/repos/apollographql/graphql-tools/issues{/number}","pulls_url":"https://api.github.com/repos/apollographql/graphql-tools/pulls{/number}","milestones_url":"https://api.github.com/repos/apollographql/graphql-tools/milestones{/number}","notifications_url":"https://api.github.com/repos/apollographql/graphql-tools/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/apollographql/graphql-tools/labels{/name}","releases_url":"https://api.github.com/repos/apollographql/graphql-tools/releases{/id}","deployments_url":"https://api.github.com/repos/apollographql/graphql-tools/deployments","created_at":"2016-03-22T00:14:38Z","updated_at":"2018-02-27T14:06:18Z","pushed_at":"2018-02-27T18:50:18Z","git_url":"git://github.com/apollographql/graphql-tools.git","ssh_url":"git@github.com:apollographql/graphql-tools.git","clone_url":"https://github.com/apollographql/graphql-tools.git","svn_url":"https://github.com/apollographql/graphql-tools","homepage":"https://www.apollographql.com/docs/graphql-tools/","size":1259,"stargazers_count":1599,"watchers_count":1599,"language":"TypeScript","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":192,"mirror_url":null,"archived":false,"open_issues_count":103,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit"},"forks":192,"open_issues":103,"watchers":1599,"default_branch":"master"}},"base":{"label":"apollographql:master","ref":"master","sha":"c78f1de52930efa5eb981b50428302656a9b59f5","user":{"login":"apollographql","id":17189275,"avatar_url":"https://avatars0.githubusercontent.com/u/17189275?v=4","gravatar_id":"","url":"https://api.github.com/users/apollographql","html_url":"https://github.com/apollographql","followers_url":"https://api.github.com/users/apollographql/followers","following_url":"https://api.github.com/users/apollographql/following{/other_user}","gists_url":"https://api.github.com/users/apollographql/gists{/gist_id}","starred_url":"https://api.github.com/users/apollographql/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apollographql/subscriptions","organizations_url":"https://api.github.com/users/apollographql/orgs","repos_url":"https://api.github.com/users/apollographql/repos","events_url":"https://api.github.com/users/apollographql/events{/privacy}","received_events_url":"https://api.github.com/users/apollographql/received_events","type":"Organization","site_admin":false},"repo":{"id":54432168,"name":"graphql-tools","full_name":"apollographql/graphql-tools","owner":{"login":"apollographql","id":17189275,"avatar_url":"https://avatars0.githubusercontent.com/u/17189275?v=4","gravatar_id":"","url":"https://api.github.com/users/apollographql","html_url":"https://github.com/apollographql","followers_url":"https://api.github.com/users/apollographql/followers","following_url":"https://api.github.com/users/apollographql/following{/other_user}","gists_url":"https://api.github.com/users/apollographql/gists{/gist_id}","starred_url":"https://api.github.com/users/apollographql/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apollographql/subscriptions","organizations_url":"https://api.github.com/users/apollographql/orgs","repos_url":"https://api.github.com/users/apollographql/repos","events_url":"https://api.github.com/users/apollographql/events{/privacy}","received_events_url":"https://api.github.com/users/apollographql/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/apollographql/graphql-tools","description":":wrench: Build, mock, and stitch a GraphQL schema using the schema language","fork":false,"url":"https://api.github.com/repos/apollographql/graphql-tools","forks_url":"https://api.github.com/repos/apollographql/graphql-tools/forks","keys_url":"https://api.github.com/repos/apollographql/graphql-tools/keys{/key_id}","collaborators_url":"https://api.github.com/repos/apollographql/graphql-tools/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/apollographql/graphql-tools/teams","hooks_url":"https://api.github.com/repos/apollographql/graphql-tools/hooks","issue_events_url":"https://api.github.com/repos/apollographql/graphql-tools/issues/events{/number}","events_url":"https://api.github.com/repos/apollographql/graphql-tools/events","assignees_url":"https://api.github.com/repos/apollographql/graphql-tools/assignees{/user}","branches_url":"https://api.github.com/repos/apollographql/graphql-tools/branches{/branch}","tags_url":"https://api.github.com/repos/apollographql/graphql-tools/tags","blobs_url":"https://api.github.com/repos/apollographql/graphql-tools/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/apollographql/graphql-tools/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/apollographql/graphql-tools/git/refs{/sha}","trees_url":"https://api.github.com/repos/apollographql/graphql-tools/git/trees{/sha}","statuses_url":"https://api.github.com/repos/apollographql/graphql-tools/statuses/{sha}","languages_url":"https://api.github.com/repos/apollographql/graphql-tools/languages","stargazers_url":"https://api.github.com/repos/apollographql/graphql-tools/stargazers","contributors_url":"https://api.github.com/repos/apollographql/graphql-tools/contributors","subscribers_url":"https://api.github.com/repos/apollographql/graphql-tools/subscribers","subscription_url":"https://api.github.com/repos/apollographql/graphql-tools/subscription","commits_url":"https://api.github.com/repos/apollographql/graphql-tools/commits{/sha}","git_commits_url":"https://api.github.com/repos/apollographql/graphql-tools/git/commits{/sha}","comments_url":"https://api.github.com/repos/apollographql/graphql-tools/comments{/number}","issue_comment_url":"https://api.github.com/repos/apollographql/graphql-tools/issues/comments{/number}","contents_url":"https://api.github.com/repos/apollographql/graphql-tools/contents/{+path}","compare_url":"https://api.github.com/repos/apollographql/graphql-tools/compare/{base}...{head}","merges_url":"https://api.github.com/repos/apollographql/graphql-tools/merges","archive_url":"https://api.github.com/repos/apollographql/graphql-tools/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/apollographql/graphql-tools/downloads","issues_url":"https://api.github.com/repos/apollographql/graphql-tools/issues{/number}","pulls_url":"https://api.github.com/repos/apollographql/graphql-tools/pulls{/number}","milestones_url":"https://api.github.com/repos/apollographql/graphql-tools/milestones{/number}","notifications_url":"https://api.github.com/repos/apollographql/graphql-tools/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/apollographql/graphql-tools/labels{/name}","releases_url":"https://api.github.com/repos/apollographql/graphql-tools/releases{/id}","deployments_url":"https://api.github.com/repos/apollographql/graphql-tools/deployments","created_at":"2016-03-22T00:14:38Z","updated_at":"2018-02-27T14:06:18Z","pushed_at":"2018-02-27T18:50:18Z","git_url":"git://github.com/apollographql/graphql-tools.git","ssh_url":"git@github.com:apollographql/graphql-tools.git","clone_url":"https://github.com/apollographql/graphql-tools.git","svn_url":"https://github.com/apollographql/graphql-tools","homepage":"https://www.apollographql.com/docs/graphql-tools/","size":1259,"stargazers_count":1599,"watchers_count":1599,"language":"TypeScript","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":192,"mirror_url":null,"archived":false,"open_issues_count":103,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit"},"forks":192,"open_issues":103,"watchers":1599,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/apollographql/graphql-tools/pulls/640"},"html":{"href":"https://github.com/apollographql/graphql-tools/pull/640"},"issue":{"href":"https://api.github.com/repos/apollographql/graphql-tools/issues/640"},"comments":{"href":"https://api.github.com/repos/apollographql/graphql-tools/issues/640/comments"},"review_comments":{"href":"https://api.github.com/repos/apollographql/graphql-tools/pulls/640/comments"},"review_comment":{"href":"https://api.github.com/repos/apollographql/graphql-tools/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/apollographql/graphql-tools/pulls/640/commits"},"statuses":{"href":"https://api.github.com/repos/apollographql/graphql-tools/statuses/21d6479016d30a72bdb3974114b29ad92f3d49e2"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"stubailo"}}