Skip to main content
Version: 7.x.x

Apollo Federation

In many cases, exposing single GraphQL API that exposes unified view of all the available data provides tremendous value to their clients. As the underlying graph scales, managing single monolithic GraphQL server might become less and less feasible making it much harder to manage and leading to unnecessary bottlenecks. Migrating towards federated model with an API gateway and a number of smaller GraphQL services behind it alleviates some of those problems and allows teams to scale their graphs more easily.

Apollo Federation is an architecture for composing multiple GraphQL services into a single graph. Federated schemas rely on a number of custom directives to instrument the behavior of the underlying graph and convey the relationships between different schema types. Each individual GraphQL server generates a valid GraphQL schema and can be run independently. This is in contrast with a traditional schema stitching approach where relationships between individual services, i.e. linking configuration, is configured at the GraphQL gateway level.

Federation v1 vs Federation v2

Federation v2 is an evolution of the Federation spec to make it more powerful, flexible and easier to adapt. While v1 and v2 schemas are similar in many ways, Federation v2 relaxes some of the constraints and adds additional capabilities. See Apollo documentation for details.

By default, graphql-kotlin-federation library will generate Federation v2 compatible schema. In order to generate v1 compatible schema you have to explicitly opt-out by specifying optInFederationV2 = false on your instance of FederatedSchemaGeneratorHooks.

val myHooks = FederatedSchemaGeneratorHooks(resolvers = myFederatedResolvers)
val myConfig = FederatedSchemaGeneratorConfig(
supportedPackages = "com.example",
hooks = myHooks
)

toFederatedSchema(
config = myConfig,
queries = listOf(TopLevelObject(MyQuery()))
)
note

When generating federated schemas, graphql-kotlin-spring-server defaults to Federation v2. If you want to generate Federation v1 schema, you have to explicitly opt-out by configuring graphql.federation.optInV2 = false property.

Install

Using a JVM dependency manager, link graphql-kotlin-federation to your project.

implementation("com.expediagroup", "graphql-kotlin-federation", latestVersion)

Usage

graphql-kotlin-federation is build on top of graphql-kotlin-schema-generator and adds a few extra methods and class to use to generate federation compliant schemas.

toFederatedSchema

Just like the basic toSchema, toFederatedSchema accepts five parameters: config, queries, mutations, subscriptions and schemaObject. The difference is that the config class is of type FederatedSchemaGeneratorConfig. This class extends the base configuration class and adds some default logic. You can override the logic if needed, but do so with caution as you may no longer generate a spec compliant schema.

You can see the definition for toFederatedSchema in the source.

Example

@KeyDirective(fields = FieldSet("id"))
data class User(
val id: ID,
val name: String
)

class Query {
fun getUsers(): List<User> = getUsersFromDB()
}

val config = FederatedSchemaGeneratorConfig(
supportedPackages = "com.example",
hooks = FederatedSchemaGeneratorHooks(emptyList())
)

toFederatedSchema(
config = config,
queries = listOf(TopLevelObject(Query()))
)

will generate

schema @link(import : ["@key", "FieldSet"], url : "https://specs.apollo.dev/federation/v2.6"){
query: Query
}

directive @key(fields: FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE
directive @link(import: [String], url: String!) repeatable on SCHEMA

type Query {
getUsers: [User!]!

_entities(representations: [_Any!]!): [_Entity]!
_service: _Service!
}

type User @key(fields : "id", resolvable : true) {
id: ID!
name: String!
}

union _Entity = User

type _Service {
sdl: String!
}

scalar FieldSet
scalar _Any