Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update mergeSchemas and delegation API, plus Schema Transfroms #527

Merged
merged 67 commits into from
Apr 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
08e2058
Next api
freiksenet Feb 15, 2018
6f3728e
mre from master
freiksenet Feb 15, 2018
9b18a78
Merge remote-tracking branch 'origin/master' into next-api
freiksenet Feb 15, 2018
0c1b48a
Make all tests pass
freiksenet Feb 15, 2018
59d2779
Namespacing schema
freiksenet Feb 20, 2018
a0e8416
Backwards compatible implementation
freiksenet Feb 21, 2018
4b108cb
Alpha 6
freiksenet Feb 21, 2018
a986cc9
More helpful warnings
freiksenet Feb 21, 2018
4fcd04b
Drop old versions
freiksenet Feb 21, 2018
a21165d
Update dependencies
freiksenet Feb 21, 2018
1c0f3f8
Lock apollo-link to lower version to avoid their bug
freiksenet Feb 21, 2018
39f1d7a
Merge remote-tracking branch 'origin/master' into next-api
freiksenet Feb 21, 2018
f914bee
Richer onTypeConflict
freiksenet Feb 26, 2018
65bd750
Alpha 7
freiksenet Feb 27, 2018
033efb5
Filtering types
freiksenet Feb 28, 2018
4a04136
Separate transforms
freiksenet Mar 1, 2018
652d608
Better
freiksenet Mar 6, 2018
0988b01
Fixed fragments
freiksenet Mar 13, 2018
d0f8d3d
Alpha 10
freiksenet Mar 13, 2018
96b78bf
Merge remote-tracking branch 'origin/master' into next-api
freiksenet Mar 13, 2018
08caa78
Starting doing the docs
freiksenet Mar 15, 2018
ec96674
Updated docs
freiksenet Mar 15, 2018
59e0da5
More docs
freiksenet Mar 16, 2018
fd8b8f0
Merge branch 'master' into next-api
freiksenet Mar 16, 2018
51d2ccf
Removed re-export
freiksenet Mar 16, 2018
e380441
Add failing spec for merging schemas w/ unions that implement an inte…
mzikherman Mar 26, 2018
23edf1a
Merge remote-tracking branch 'mzikherman/unions_and_interfaces' into …
freiksenet Apr 2, 2018
6b7a1ce
Expand new interfaces to their implementations
freiksenet Apr 2, 2018
27bd1d8
Alpha 11
freiksenet Apr 2, 2018
ed681c9
Older graphql support
freiksenet Apr 2, 2018
07d2f72
Fix older graphql v2
freiksenet Apr 2, 2018
a0780f5
Merge branch 'master' into next-api
freiksenet Apr 2, 2018
a0e5e2c
Add __typename at expansion
freiksenet Apr 2, 2018
388973a
Alpha 12
freiksenet Apr 2, 2018
04b659e
Fix more issues with abstract types
freiksenet Apr 3, 2018
4bffa18
Alpha 13
freiksenet Apr 3, 2018
a19d94a
Rollback to old API
freiksenet Apr 3, 2018
0db0123
Alpha 14
freiksenet Apr 3, 2018
54d140a
Merge branch 'master' into next-api
freiksenet Apr 5, 2018
3b71ebc
graphql -> execute (#710)
Apr 5, 2018
c3aaf92
Rename makeTransformSchema to transformSchema.
benjamn Apr 4, 2018
cf2c921
Add back Travis CI testing in Node 4.
benjamn Apr 4, 2018
b740ede
Limit transforms/index.ts re-exports as much as possible.
benjamn Apr 4, 2018
55eb147
First pass at editing schema-delegation.md.
benjamn Apr 4, 2018
8fb3b45
Make delegateToSchema take named rather than positional parameters.
benjamn Apr 5, 2018
dbee260
Make additional args optional when calling delegateToSchema.
benjamn Apr 5, 2018
8970eaa
Merge remote-tracking branch 'origin/master' into next-api
freiksenet Apr 17, 2018
cabbd94
Remove transform warnings
freiksenet Apr 17, 2018
2e14209
Alpha 15
freiksenet Apr 17, 2018
663c9af
Don't overuse fragments that won't be valid
freiksenet Apr 17, 2018
fa1228c
Alpha 16
freiksenet Apr 17, 2018
101fd40
Fix examples of delegateToSchema (#742)
kuzmiigo Apr 18, 2018
370e701
Added Changelog
freiksenet Apr 19, 2018
62972c3
Update schema-transforms.md
freiksenet Apr 20, 2018
341a4ba
Move everything to be a class
freiksenet Apr 20, 2018
f0219e0
Make delegate to schema backwards compatible
freiksenet Apr 20, 2018
0e92f24
Merge branch 'master' into next-api
freiksenet Apr 20, 2018
1116562
Minor tweaks to schema-delegation.md.
benjamn Apr 20, 2018
e3634d6
Editing pass over schema-stitching.md.
benjamn Apr 20, 2018
193aaa6
Define reusable IResolversParameterType.
benjamn Apr 20, 2018
dc5187f
Reimplement RenameTypes#transformResult without using visitObject.
benjamn Apr 20, 2018
452586a
Rearrange and simplify v3.0.0 CHANGELOG.md section.
benjamn Apr 20, 2018
e5eb694
Editing pass over schema-transforms.md.
benjamn Apr 20, 2018
169e698
Rename Boolean (object) type annotations to boolean (primitive).
benjamn Apr 20, 2018
9b834b4
Remove qualified export, add wrapquery and extractfield
freiksenet Apr 23, 2018
fa9af99
Merge branch 'master' into next-api
freiksenet Apr 23, 2018
adb1a7f
Code coverage fixes.
benjamn Apr 23, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
!dist/
!dist/*
!dist/stitching/*
!dist/transforms/*
!package.json
!*.md
!*.png
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,5 @@ script:
sudo: false

env:
- GRAPHQL_VERSION='^0.11'
- GRAPHQL_VERSION='^0.12'
- GRAPHQL_VERSION='^0.13'
17 changes: 13 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
# Change log

### vNEXT

* add commentDescription to printSchema call to match other uses [PR #745](https://github.com/apollographql/graphql-tools/pull/745)
* Add `createResolver` option to `makeRemoteExecutableSchema` [PR #734](https://github.com/apollographql/graphql-tools/pull/734)
### v3.0.0 (prerelease)

* Schema transforms and delegation
* Substantial rewrite of internals of `mergeSchemas` and `delegateToSchema`
* A new API for schema transforms has been introduced: [Docs](https://www.apollographql.com/docs/graphql-tools/schema-transforms.html)
* `delegateToSchema` is now a public API [Docs](https://www.apollographql.com/docs/graphql-tools/schema-delegation.html)
* `delegateToSchema` now accepts an object of named parameters; positional arguments are deprecated
* `delegateToSchema` no longer accepts `fragmentReplacements`, instead accepting `transforms`
* `info.mergeInfo.delegateToSchema` is now the preferred delegation API, rather than `info.mergeInfo.delegate` (deprecated)

* Other changes
* add commentDescription to printSchema call to match other uses [PR #745](https://github.com/apollographql/graphql-tools/pull/745)
* Add `createResolver` option to `makeRemoteExecutableSchema` [PR #734](https://github.com/apollographql/graphql-tools/pull/734)

### v2.24.0

Expand Down
4 changes: 3 additions & 1 deletion docs/_config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ sidebar_categories:
- scalars
- mocking
- connectors
- remote-schemas
- schema-directives
- schema-delegation
- remote-schemas
- schema-transforms
- schema-stitching
Related:
- title: Monitoring and caching
Expand Down
200 changes: 200 additions & 0 deletions docs/source/schema-delegation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
---
title: Schema delegation
description: Forward queries to other schemas automatically
---

Schema delegation is a way to automatically forward a query (or a part of a query) from a parent schema to another schema (called a _subschema_) that is able to execute the query. Delegation is useful when the parent schema shares a significant part of its data model with the subschema. For example, the parent schema might be powering a GraphQL gateway that connects multiple existing endpoints together, each with its own schema. This kind of architecture could be implemented using schema delegation.

The `graphql-tools` package provides several related tools for managing schema delegation:

* [Remote schemas](./remote-schemas.html) - turning a remote GraphQL endpoint into a local schema
* [Schema transforms](./schema-transforms.html) - modifying existing schemas to make delegation easier
* [Schema stitching](./schema-stitching) - merging multiple schemas into one

Delegation is performed by one function, `delegateToSchema`, called from within a resolver function of the parent schema. The `delegateToSchema` function sends the query subtree received by the parent resolver to a subschema that knows how to execute it, then returns the result as if the parent resolver had executed the query.

<h2 id="example">Motivational example</h2>

Let's consider two schemas, a subschema and a parent schema that reuses parts of a subschema. While the parent schema reuses the *definitions* of the subschema, we want to keep the implementations separate, so that the subschema can be tested independently, or even used as a remote service.

```graphql
# Subschema
type Repository {
id: ID!
url: String
issues: [Issue]
userId: ID!
}

type Issue {
id: ID!
text: String!
repository: Repository!
}

type Query {
repositoryById(id: ID!): Repository
repositoriesByUserId(id: ID!): [Repository]
}

# Parent schema
type Repository {
id: ID!
url: String
issues: [Issue]
userId: ID!
user: User
}

type Issue {
id: ID!
text: String!
repository: Repository!
}

type User {
id: ID!
username: String
repositories: [Repository]
}

type Query {
userById(id: ID!): User
}
```

Suppose we want the parent schema to delegate retrieval of repositories to the subschema, in order to execute queries such as this one:

```graphql
query {
userById(id: "1") {
id
username
repositories {
id
url
user
issues {
text
}
}
}
}
```

The resolver function for the `repositories` field of the `User` type would be responsible for the delegation, in this case. While it's possible to call a remote GraphQL endpoint or resolve the data manually, this would require us to transform the query manually, or always fetch all possible fields, which could lead to overfetching. Delegation automatically extracts the appropriate query to send to the subschema:

```graphql
# To the subschema
query($id: ID!) {
repositoriesByUserId(id: $id) {
id
url
issues {
text
}
}
}
```

Delegation also removes the fields that don't exist on the subschema, such as `user`. This field would be retrieved from the parent schema using normal GraphQL resolvers.

<h2 id="api">API</h2>

<h3 id="delegateToSchema">delegateToSchema</h3>

The `delegateToSchema` method can be found on the `info.mergeInfo` object within any resolver function, and should be called with the following named options:

```
delegateToSchema(options: {
schema: GraphQLSchema;
operation: 'query' | 'mutation' | 'subscription';
fieldName: string;
args?: { [key: string]: any };
context: { [key: string]: any };
info: GraphQLResolveInfo;
transforms?: Array<Transform>;
}): Promise<any>
```

#### schema: GraphQLSchema

A subschema to delegate to.

#### operation: 'query' | 'mutation' | 'subscription'

The operation type to use during the delegation.

#### fieldName: string

A root field in a subschema from which the query should start.

#### args: { [key: string]: any }

Additional arguments to be passed to the field. Arguments passed to the field that is being resolved will be preserved if the subschema expects them, so you don't have to pass existing arguments explicitly, though you could use the additional arguments to override the existing ones. For example:

```graphql
# Subschema

type Booking {
id: ID!
}

type Query {
bookingsByUser(userId: ID!, limit: Int): [Booking]
}

# Schema

type User {
id: ID!
bookings(limit: Int): [Booking]
}

type Booking {
id: ID!
}
```

If we delegate at `User.bookings` to `Query.bookingsByUser`, we want to preserve the `limit` argument and add an `userId` argument by using the `User.id`. So the resolver would look like the following:

```js
const resolvers = {
User: {
bookings(parent, args, context, info) {
return info.mergeInfo.delegateToSchema({
schema: subschema,
operation: 'query',
fieldName: 'bookingsByUser',
args: {
userId: parent.id,
},
context,
info,
);
},
...
},
...
};
```

#### context: { [key: string]: any }

GraphQL context that is going to be past to subschema execution or subsciption call.

#### info: GraphQLResolveInfo

GraphQL resolve info of the current resolver. Provides access to the subquery that starts at the current resolver.

Also provides the `info.mergeInfo.delegateToSchema` function discussed above.

#### transforms: Array<Transform>

[Transforms](./transforms.html) to apply to the query and results. Should be the same transforms that were used to transform the schema, if any. After transformation, `transformedSchema.transforms` contains the transforms that were applied.

<h2 id="considerations">Additional considerations</h2>

### Aliases

Delegation preserves aliases that are passed from the parent query. However that presents problems, because default GraphQL resolvers retrieve field from parent based on their name, not aliases. This way results with aliases will be missing from the delegated result. `mergeSchemas` and `transformSchemas` go around that by using `src/stitching/defaultMergedResolver` for all fields without explicit resolver. When building new libraries around delegation, one should consider how the aliases will be handled.
Loading