Support For Apollo Federation

Motivaton

Extend support for Apollo Federation according to the federation specs

User Impact

Users will now be able to use the Apollo federation server which provides a unified interface for querying any combination of GraphQL backend services.

Implementation

Introduction

According to the federation docs, the architecture of federation consists of 2 components:-
1- Collection of GraphQL servers also known as implementing services.
2 - A Gateway that essentially constructs a federated Graph from the schemas of those distinct implementing services.

Gateway is basically a query planner that breaks a GraphQL query and fetch data from different implementing services according to where the data is stored.

Implementation

In order to extend support for federation, we need to implement the federation schema specification and generate resolver for entities.
We need to implement the following additions to the schema:

scalar _Any
scalar _FieldSet

# a union of all types that use the @key directive
union _Entity

type _Service {
  sdl: String
}

extend type Query {
  _entities(representations: [_Any!]!): [_Entity]!
  _service: _Service!
}

directive @external on FIELD_DEFINITION
directive @requires(fields: _FieldSet!) on FIELD_DEFINITION
directive @provides(fields: _FieldSet!) on FIELD_DEFINITION
directive @key(fields: _FieldSet!) on OBJECT | INTERFACE
directive @extends on OBJECT | INTERFACE

We will not be extending support for @provides and @requires directive initially.

What is an Entity?

According to the federation docs, an entity is a type that we define in one implementing service and extend it in other services. These are the core building blocks of the federated graph.
It is denoted by adding a @key directive to the definition.
for eg:

type Product @key(fields: "upc") {
  upc: String!
  name: String!
  price: Int
}

The field which is given as an argument to the @key directive must be a primary key. In our case, it should be of the ID type or have an @id directive.

Note: Federation specs allow defining multiple primary keys or compound primary keys but we will not implement it now for the sake of simplicity.

Type Extension

Since federation encourages the principle of separation of concern for the schema designing which allows us to define one type in one implementing service and extend it in other services.
Suppose for the given schema:

type User {
 name: String
 recentPurchases: [Product]
 reviews: [Review]
}
type Product {
 name: String
 price: String
 reviews: [Review]
}
type Review {
 body: String
 author: User
 product: Product
}

If we were to break it into 3 implementing services concerning User, Product, and Review.
It will be as follows:
Service1:

type User {
 name: String
}

Service2:

type Product {
 name: String
 price: String
}
extend type User {
 recentPurchases: [Product]
}

Service3:

type Review {
 body: String
 author: User
 product: Product
}
extend type User {
 reviews: [Review]
}
extend type Product {
 reviews: [Review]
}

We will allow type extension with both extend keyword and @extends` directive. Then it will look something like this:

type User @extends{
 recentPurchases: [Product]
}

or

extend type User {
 recentPurchases: [Product]
}

Entity Resolvers:

For an implementing service to reference a type that is defined in some other implementing service, we need entity resolvers which takes __typename and primary key of that type and returns a unique object. It will closely follow the definition given here

References:

https://discuss.dgraph.io/t/graphql-apollo-federation-demo/5130/

4 Likes

Awesome news!

Wondering if it is on a roadmap and what priority this feature has? (e.g. should we wait for it in Q1 or Q4)

Also it will solve this one Input with a __typename field (federated dgraph) - #2 by amaster507

Initial implementation of Apollo federation is completed and it should be available with the next release.
Feel free to try it out on master branch and suggest the improvements over it. We are actively seeking feedback.

A post was split to a new topic: Cannot query field “_service” on type “Query”