-
Notifications
You must be signed in to change notification settings - Fork 66
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
Docs (GraphQL): 21.03 feature documentation for federation #104
Changes from 4 commits
2487e60
efe7e90
e6b8314
defa5c4
3c382eb
12bc2f5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,163 @@ | ||||||
+++ | ||||||
title = "Apollo Federation" | ||||||
description = "Dgraph now supports Apollo federation so that you can create a gateway GraphQL service that includes the Dgraph GraphQL API and other GraphQL services." | ||||||
weight = 14 | ||||||
[menu.main] | ||||||
name = "Apollo Federation" | ||||||
identifier = "federation" | ||||||
parent = "graphql" | ||||||
+++ | ||||||
|
||||||
Dgraph supports Apollo federation starting in release version 21.03. This lets you create a gateway GraphQL service that includes the Dgraph GraphQL API and other GraphQL services. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
## Support for Apollo federation directives | ||||||
|
||||||
The current implementation supports the following five directives: `@key`, `@extends`, `@external`, `@provides`, and `@requires`. | ||||||
|
||||||
### `@key` directive | ||||||
This directive takes one field argument inside it: the `@key` field. There are few limitations on how to use `@key` directives: | ||||||
|
||||||
- Users can define the @key directive only once for a type | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
- Support for multiple key types is not currently available. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
- Since the @key field acts as a foreign key to resolve entities from the service where it is extended, the field provided as an argument inside the @key directive should be of ID type or have the @id directive on it. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
For example - | ||||||
|
||||||
```graphql | ||||||
type User @key(fields: "id") { | ||||||
id: ID! | ||||||
name: String | ||||||
} | ||||||
``` | ||||||
|
||||||
### `@extends` directive | ||||||
This directive is provided to give support for extended definitions. Suppose the above defined `User` type is defined in some service. Users can extend it to our GraphQL service by using this directive. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
We can also add that the same is also achievable with the |
||||||
```graphql | ||||||
type User @key(fields: "id") @extends{ | ||||||
id: ID! @external | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Let's use this, so that we have both the syntax for |
||||||
products: [Product] | ||||||
} | ||||||
``` | ||||||
|
||||||
### `@external` directive | ||||||
This directive is used when the given field is not stored in this service. It can only be used on extended type definitions. As it is used above on the `id` field of `User` type. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
### `@provides` directive | ||||||
This directive is used on a field that tells the gateway to return a specific fieldSet from the base type while fetching the field. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Per https://www.apollographql.com/docs/federation/federation-spec/#scalar-_fieldset, we should either write "fieldset" or |
||||||
|
||||||
For example - | ||||||
|
||||||
```graphql | ||||||
type Review @key(fields: "id") { | ||||||
product: Product @provides(fields: "name price") | ||||||
} | ||||||
|
||||||
extend type Product @key(fields: "upc") { | ||||||
upc: String @external | ||||||
name: String @external | ||||||
price: Int @external | ||||||
} | ||||||
``` | ||||||
|
||||||
While fetching `Review.product` from the `review` service, and if the `name` or `price` is also queried, the gateway will fetch these from the `review` service itself, meaning that it also resolves these fields, even though both fields are `@external`. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Breaking this into two sentences makes it easier to parse (and machine-translate) |
||||||
|
||||||
### `@requires` directive | ||||||
This directive is used on a field to annotate the fieldSet of the base type. It is used to develop a query plan where the required fields may not be needed by the client, but the service may need additional information from other services. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
For example - | ||||||
|
||||||
```graphql | ||||||
extend type User @key(fields: "id") { | ||||||
id: ID! @external | ||||||
email: String @external | ||||||
reviews: [Review] @requires(fields: "email") | ||||||
} | ||||||
``` | ||||||
|
||||||
When the gateway fetches `user.reviews` from the `review` service, the gateway will get `user.email` from the `User` service and provide it as an argument to the `_entities` query. | ||||||
|
||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. About
See, this PR for example usage of |
||||||
## Generated queries and mutations | ||||||
|
||||||
In this section, you will see what all queries and mutations will be available to individual service and to the Apollo gateway. | ||||||
|
||||||
Let's take the below schema as an example - | ||||||
|
||||||
```graphql | ||||||
type Mission @key(fields: "id") { | ||||||
id: ID! | ||||||
crew: [Astronaut] | ||||||
designation: String! | ||||||
startDate: String | ||||||
endDate: String | ||||||
} | ||||||
|
||||||
type Astronaut @key(fields: "id") @extends { | ||||||
id: ID! @external | ||||||
missions: [Mission] | ||||||
} | ||||||
``` | ||||||
|
||||||
The queries and mutations which are exposed to the gateway are - | ||||||
|
||||||
```graphql | ||||||
type Query { | ||||||
getMission(id: ID!): Mission | ||||||
queryMission(filter: MissionFilter, order: MissionOrder, first: Int, offset: Int): [Mission] | ||||||
aggregateMission(filter: MissionFilter): MissionAggregateResult | ||||||
} | ||||||
|
||||||
type Mutation { | ||||||
addMission(input: [AddMissionInput!]!): AddMissionPayload | ||||||
updateMission(input: UpdateMissionInput!): UpdateMissionPayload | ||||||
deleteMission(filter: MissionFilter!): DeleteMissionPayload | ||||||
addAstronaut(input: [AddAstronautInput!]!): AddAstronautPayload | ||||||
updateAstronaut(input: UpdateAstronautInput!): UpdateAstronautPayload | ||||||
deleteAstronaut(filter: AstronautFilter!): DeleteAstronautPayload | ||||||
} | ||||||
``` | ||||||
|
||||||
The queries for `Astronaut` are not exposed to the gateway since it will be resolved through the `_entities` resolver. Although these queries will be available on the Dgraph GraphQL API endpoint. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
## Mutation for `extended` types | ||||||
If you want to add an object of `Astronaut` type which is extended in this service. | ||||||
The mutation `addAstronaut` takes `AddAstronautInput` which is generated as - | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
```graphql | ||||||
input AddAstronautInput { | ||||||
id: ID! | ||||||
missions: [MissionRef] | ||||||
} | ||||||
``` | ||||||
|
||||||
Even though the `id` field is of `ID` type which should be ideally generated internally by Dgraph. In this case, it should be provided as input since currently federated mutations aren't supported. The user should provide the value of `id` same as the value present in the GraphQL service where the type `Astronaut` is defined. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
For example, let's take that the type `Astronaut` is defined in some other service `AstronautService` as - | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
```graphql | ||||||
type Astronaut @key(fields: "id") { | ||||||
id: ID! | ||||||
name: String! | ||||||
} | ||||||
``` | ||||||
|
||||||
When adding an object of type `Astronaut`, first it should be added into `AstronautService` service and then the `addAstronaut` mutation should be called with value of `id` provided as an argument which must be equal to the value in `AstronautService` service. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
Use the admin endpoint to query for the generated schema - | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's remove the |
||||||
|
||||||
```graphql | ||||||
{ | ||||||
getGQLSchema { | ||||||
generatedSchema | ||||||
} | ||||||
} | ||||||
``` | ||||||
|
||||||
{{% notice "note" %}} | ||||||
Currently we only support federated queries, not federated mutations. We might support it in the future. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The apollo spec itself doesn't support federated mutations. So, I don't think we should even say that we might support them later. |
||||||
{{% /notice %}} | ||||||
|
||||||
## Gateway supported directives | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I feel this section is also irrelevant to users. They shouldn't be concerned about the bugs in the underlying libs. They only want to use the feature. |
||||||
|
||||||
Due to the bug in the federation library (see [here](https://github.com/apollographql/federation/issues/346)), some directives are removed from the schema `SDL` which is returned to the gateway in response to the `_service` query. Those directives are `@custom`, `@generate`, and `@auth`. | ||||||
|
||||||
You can still use these directives in your GraphQL schema and they will work as desired but the gateway will unaware of this. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a "description" under "title" to give us a description for SEO. Suggestion:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for adding this!