Skip to content

Commit

Permalink
reintegration
Browse files Browse the repository at this point in the history
  • Loading branch information
alinsimoc committed Jun 24, 2021
1 parent 7d3e300 commit 77a3399
Show file tree
Hide file tree
Showing 62 changed files with 653 additions and 1,087 deletions.
26 changes: 0 additions & 26 deletions website/.gitignore

This file was deleted.

42 changes: 0 additions & 42 deletions website/README.md

This file was deleted.

File renamed without changes.
178 changes: 178 additions & 0 deletions website/docs/guides/directive-resolvers.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
---
id: directive-resolvers
title: Directive resolvers
description: A set of utilities to build your JavaScript GraphQL schema in a concise and powerful way.
---

## Directive example

Let's take a look at how we can create `@upper` Directive to upper-case a string returned from resolve on Field

To start, let's grab the schema definition string from the `makeExecutableSchema` example [in the "Generating a schema" article](/docs/generate-schema/#example).

```js
import { makeExecutableSchema } from '@graphql-tools/schema';
import { graphql } from 'graphql';

// Construct a schema, using GraphQL schema language
const typeDefs = `
directive @upper on FIELD_DEFINITION
type Query {
hello: String @upper
}
`;

// Implement resolvers for out custom Directive
const directiveResolvers = {
upper(
next,
src,
args,
context,
) {
return next().then((str) => {
if (typeof(str) === 'string') {
return str.toUpperCase();
}
return str;
});
},
}

// Provide resolver functions for your schema fields
const resolvers = {
Query: {
hello: (root, args, context) => {
return 'Hello world!';
},
},
};

export const schema = makeExecutableSchema({
typeDefs,
resolvers,
directiveResolvers,
});

const query = `
query UPPER_HELLO {
hello
}
`;

graphql(schema, query).then((result) => console.log('Got result', result));
```

> Note: next() always return a Promise for consistency, resolved with original resolver value or rejected with an error.
## Multi-Directives example

Multi-Directives on a field will be apply with LTR order.

```js
// graphql-tools combines a schema string with resolvers.
import { makeExecutableSchema } from '@graphql-tools/schema';

// Construct a schema, using GraphQL schema language
const typeDefs = `
directive @upper on FIELD_DEFINITION
directive @concat(value: String!) on FIELD_DEFINITION
type Query {
foo: String @concat(value: "@gmail.com") @upper
}
`;

// Customs directives, check https://github.com/ardatan/graphql-tools/pull/518
// for more examples
const directiveResolvers = {
upper(
next,
src,
args,
context,
) {
return next().then((str) => {
if (typeof(str) === 'string') {
return str.toUpperCase();
}
return str;
});
},
concat(
next,
src,
args,
context,
) {
return next().then((str) => {
if (typeof(str) !== 'undefined') {
return `${str}${args.value}`;
}
return str;
});
},
}

// Provide resolver functions for your schema fields
const resolvers = {
Query: {
foo: (root, args, context) => {
return 'foo';
},
},
};

// Required: Export the GraphQL.js schema object as "schema"
export const schema = makeExecutableSchema({
typeDefs,
resolvers,
directiveResolvers,
});
```

The result with query `{foo}` will be:
```json
{
"data": {
"foo": "FOO@GMAIL.COM"
}
}
```

## API

### directiveResolvers option

```js
import { makeExecutableSchema } from '@graphql-tools/schema';

const directiveResolvers = {
// directive resolvers implement
};

const schema = makeExecutableSchema({
// ... other options
directiveResolvers,
})
```

`makeExecutableSchema` has new option field is `directiveResolvers`, a map object for custom Directive's resolvers.

### attachDirectiveResolvers

```js
import { attachDirectiveResolvers } from '@graphql-tools/schema';

const directiveResolvers = {
// directive resolvers implement
};

schemaWithDirectiveResolvers = attachDirectiveResolvers(
schema,
directiveResolvers,
);
```

Given an instance of GraphQLSchema and a `directiveResolvers` map object, `attachDirectiveResolvers` returns a new schema in which all fields' resolver have been wrapped with directive resolvers.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -261,3 +261,23 @@ const schema = wrapSchema({
```

Note that within the `defaultCreateProxyingResolver` function, `delegateToSchema` receives `executor` and `subscriber` functions stored on the subschema config object originally passed to `wrapSchema`. As above, use of the the `createProxyingResolver` option is helpful when you want to customize additional functionality at resolver creation time. If you just want to customize how things are proxied at the time that they are proxied, you can make do just with custom executors and subscribers.

### makeRemoteExecutableSchema(options)

What about `makeRemoteExecutableSchema`, the function used in older versions to access remote schemas? It still works -- just now under the hood calling `wrapSchema`. There is essentially no longer any need to use `makeRemoteExecutableSchema` directly, but we've kept it around for backwards compatibility.

You can still pass a `createResolver` function to `makeRemoteExecutableSchema` to override how the fetch resolvers are created and executed. The `createResolver` param accepts an `Executor` as its first argument (and a `Subscriber` as its second) and returns a resolver function. This opens up the possibility for users to create batching mechanisms for fetches. As above, it is likely easier to just customize the `executor` function itself.

Given a GraphQL.js schema (can be a non-executable client schema made by `buildClientSchema`) and a [executor](#creating-an-executor), `makeRemoteExecutableSchema` produce a GraphQL Schema that routes all requests to the executor:

```js
import { makeRemoteExecutableSchema } from '@graphql-tools/wrap';

const createResolver: (executor: Executor) => GraphQLFieldResolver<any, any> = // . . .

const schema = makeRemoteExecutableSchema({
schema,
executor,
createResolver
});
```
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -615,9 +615,9 @@ function uniqueIDDirective(directiveName: string) {
resolve(object: any) {
const hash = createHash('sha1');
hash.update(type.name);
for (const fieldName of from) {
from.forEach((fieldName: string) => {
hash.update(String(object[fieldName]));
}
});
return hash.digest('hex');
},
};
Expand Down Expand Up @@ -702,7 +702,7 @@ export function attachDirectiveResolvers(
const newFieldConfig = { ...fieldConfig };

const directives = getDirectives(schema, fieldConfig);
for (const directiveName in directives) {
Object.keys(directives).forEach(directiveName => {
if (directiveResolvers[directiveName]) {
const resolver = directiveResolvers[directiveName];
const originalResolver = newFieldConfig.resolve != null ? newFieldConfig.resolve : defaultFieldResolver;
Expand All @@ -724,7 +724,7 @@ export function attachDirectiveResolvers(
);
};
}
}
});

return newFieldConfig;
},
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Note that schema stitching is a superset of the [schema wrapping](/docs/schema-w

One of the main benefits of GraphQL is that we can query for all data in a single request to one schema. As that schema grows though, it may become preferable to break it up into separate modules or microservices that can be developed independently. We may also want to integrate the schemas we own with third-party schemas, allowing mashups with external data.

![distributed service graph](../static/img/distributed-graph.png)
![distributed service graph](/assets/distributed-graph.png)

In these cases, `stitchSchemas` is used to combine multiple GraphQL APIs into one unified gateway proxy schema that knows how to delegate parts of a request to the relevant underlying subschemas. These subschemas may be local GraphQL instances or APIs running on remote servers.

Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ This fabricated record fulfills the not-null requirement of the `posts:[Post]!`

To better understand the flow of merged object calls, let's break down the [basic example](#basic-example) above:

![Schema Stitching flow](../static/img/stitching-flow.png)
![Schema Stitching flow](/assets/stitching-flow.png)

1. A request is submitted to the gateway schema that selects fields from multiple subschemas.
2. The gateway fetches the resource that was **explicitly** requested (`userById`), known as the _original object_. This subquery is filtered to match its subschema, and adds the `selectionSet` of other subschemas that must **implicitly** provide data for the request.
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit 77a3399

Please sign in to comment.