UNPKG

6.68 kBMarkdownView Raw
1# graphql-toolkit
2
3A set of utils for faster development of GraphQL tools. Use these utils if you are creating a tool that loads schema/documents, merges schemas, scan for schema/documents/resolvers files.
4
5Included tools:
6
7### Schema Loading
8
9These utils are useful for scanning, loading and building a GraphQL schema from any input.
10
11You can either specify a GraphQL endpoint, local introspection JSON file, code file that `export`s a GraphQLSchema, AST string and `.graphql` files (with support for `glob` expression).
12
13It also merges all found schema files into a complete schema, and has support for `#import` syntax (using [`graphql-import`](https://github.com/prisma/graphql-import)).
14
15You can also extend the loads by implementing you own loader (implement the interface `SchemaLoader`).
16
17The schema loading util is using loaders, and implemented using [chain-of-responsibility pattern](https://en.wikipedia.org/wiki/Chain-of-responsibility_pattern).
18
19You don't have to specify which loader to use - just provide your input and this utils will detect it automatically.
20
21Usage:
22
23```ts
24import { loadSchema } from 'graphql-toolkit';
25
26const schema1 = loadSchema('type A { foo: String }'); // load from string
27const schema2 = loadSchema('http://localhost:3000/graphql'); // load from endpoint
28const schema3 = loadSchema('./schema.json'); // load from local json file
29const schema4 = loadSchema('schema.graphql'); // load from a single schema file
30const schema5 = loadSchema('./src/**/*.graphql'); // load from multiple files using glob
31```
32
33### Documents Loading
34
35Similar to schema loading - but meant to use for GraphQL documents (query/mutation/subscription/fragment).
36
37You an specify any input as source, and this utils will detect it automatically.
38
39It also extracts usages of `gql` from code files using [`graphql-tag-pluck`](https://github.com/DAB0mB/graphql-tag-pluck).
40
41Usage:
42
43```ts
44import { loadDocuments } from 'graphql-toolkit';
45
46const document1 = loadDocuments('query { f }'); // load from string
47const document2 = loadDocuments('./users.query.graphql'); // load from a single file
48const document3 = loadDocuments('./src/**/*.graphql'); // load from multiple files using glob
49const document4 = loadDocuments('./src/my-component.ts'); // load from code file
50```
51
52### Epoxy
53
54Originally implemented in [graphql-modules](https://github.com/Urigo/graphql-modules). This tools merged GraphQL type definitions and schema. It aims to merge all possible types, interfaces, enums and unions, without conflicts.
55
56It also merged resolvers by using deep-merge, so you can separate your resolvers implementating across multiple objects and the merge it into a single `resolvers` object.
57
58```graphql
59# a1.graphql
60type A {
61 f1: String
62}
63
64# a2.graphql
65type A {
66 f2: String
67}
68```
69
70Will result:
71```graphql
72type A {
73 f1: String
74 f2: String
75}
76```
77
78### Sonar
79
80Sonar is a small util that scans you file-system and find GraphQL files (`.graphql`) and resolvers files (`.js`/`.ts`) and loads them (using `readFile` for GraphQL files and `require` for resolvers files).
81
82### Other Utils
83
84There are some more utils under `utils` directory:
85
86#### `validateGraphQlDocuments`
87
88A tool for validating GraphQL documents (query/mutation/subscription/fragment) against the schema.
89
90It uses the original validation logic from `graphql` package, but suspressing some validation rules, and focuses on validating the fields and the structure of the documents.
91
92#### `extractDocumentStringFromCodeFile`
93
94This method gets a source code file, and using `graphql-tag-pluck` tries to extract GraphQL AST from it.
95
96#### `getDirectives`
97
98This method accepts `GraphQLSchema` and any AST node, and tries to extract the GraphQL directives of the AST node.
99
100It returnes a `Map` of the directive name and the arguments of it.
101
102#### `getFieldsWithDirectives`
103
104This method accepts a GraphQL `DocumentNode` of a GraphQL types definition and creates a map between GraphQL `type.field` and the directives it has.
105
106It's useful for getting an easy-to-use structure of the directives that are decorating the schema.
107
108#### `getImplementingTypes`
109
110This method accepts `GraphQLSchema` object and a name of a GraphQL interface, and returns an array of all the GraphQL types that are implementing the GraphQL `interface`.
111
112#### `getSchemaDirectiveFromDirectiveResolver`
113
114This method accepts a name of a GraphQL Directive and its resolver function; using this method you can easily generate `SchemaDirective` with a single resolver function.
115
116#### `composeResolvers`
117
118This method accepts `IResolvers` object and mappings for composition functions that would be run before resolver itself.
119
120Instead of doing this,
121
122```js
123const resolvers ={
124 Query: {
125 myQuery: (root, args, context) => {
126 // Make sure that the user is authenticated
127 if (!context.currentUser) {
128 throw new Error('You are not authenticated!');
129 }
130
131 // Make sure that the user has the correct roles
132 if (!context.currentUser.roles || context.currentUser.roles.includes('EDITOR')) {
133 throw new Error('You are not authorized!');
134 }
135
136 // Business logic
137 if (args.something === '1') {
138 return true;
139 }
140
141 return false;
142 },
143 },
144};
145```
146
147You can do;
148
149```js
150const resolvers ={
151 Query: {
152 myQuery: (root, args, context) => {
153 if (args.something === '1') {
154 return true;
155 }
156
157 return false;
158 },
159 },
160};
161
162const isAuthenticated = () => next => async (root, args, context, info) => {
163 if (!context.currentUser) {
164 throw new Error('You are not authenticated!');
165 }
166
167 return next(root, args, context, info);
168};
169
170const hasRole = (role: string) => next => async (root, args, context, info) => {
171 if (!context.currentUser.roles || context.currentUser.roles.includes(role)) {
172 throw new Error('You are not authorized!');
173 }
174
175 return next(root, args, context, info);
176};
177
178const resolversComposition = {
179 'Query.myQuery': [isAuthenticated(), hasRole('EDITOR')],
180};
181
182const composedResolvers = composeResolvers(resolvers, resolversComposition);
183```
184
185#### `extractResolversFromSchema`
186
187This methods accepts `GraphQLSchema` object, and returns a map with field resolver functions of all types inside the schema as in [`IResolvers` interface of `graphql-tools`.](https://www.apollographql.com/docs/graphql-tools/resolvers.html)
188
189#### `extractFieldResolversFromObjectType`
190
191This methods accepts `GraphQLObjectType` or `GraphQLInterfaceType` object, and returns a map with field resolvers of given type.