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.
Install
Using a JVM dependency manager, link graphql-kotlin-federation
to your project.
- Gradle Kotlin
- Maven
implementation("com.expediagroup", "graphql-kotlin-federation", latestVersion)
<dependency>
<groupId>com.expediagroup</groupId>
<artifactId>graphql-kotlin-federation</artifactId>
<version>${latestVersion}</version>
</dependency>
Usage
graphql-kotlin-federation
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 four parameters: config
, queries
, mutations
and subscriptions
.
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"
)
toFederatedSchema(
config = config,
queries = listOf(TopLevelObject(Query()))
)
will generate
# Federation spec types
scalar _Any
scalar _FieldSet
union _Entity
type _Service {
sdl: String!
}
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
# Schema types
type Query @extends {
getUsers: [User!]!
_entities(representations: [_Any!]!): [_Entity]!
_service: _Service!
}
type User @key(fields : "id") {
id: ID!
name: String!
}