sangria-federated is a library that allows sangria users to implement services that adhere to Apollo's Federation Specification, and can be used as part of a federated data graph.
SBT Configuration:
libraryDependencies += "org.sangria-graphql" %% "sangria-federated" % "<latest version>"
The library adds Apollo's Federation Specification on top of the provided sangria graphql schema.
To make it possible to use _Any
as a scalar, the library upgrades the used marshaller.
A good example showing all different features is the sangria implementation of the Apollo Federation Subgraph Compatibility.
All the code of this example is available here.
To be able to communicate with Apollo's federation gateway, the graphql sangria service should be using both the federated schema and unmarshaller.
As an example, let's consider the following services:
- a review service provides a subgraph for review
- a state service provides a subgraph for states. This state is used by reviews.
- both subgraphs are composed into one supergraph that is the only graph exposed to users. With that, users can interact with reviews and states as if they were implemented in one service.
The state service defines the state entity annotated with @key("id")
.
For each entity, we need to define an entity resolver.
It's highly recommended to use Deferred Value Resolution in those resolvers to batch the fetching of the entities.
Implementation of the State GraphQL API.
The entity resolver implements:
- the deserialization of the fields in
_Any
object to the EntityArg. - how to fetch the proper Entity (in our case
State
) based on the EntityArg.
In the definition of the GraphQL server, we federate the Query type and the unmarshaller while supplying the entity resolvers. Then, we use both the federated schema and unmarshaller as arguments for the server:
def graphQL[F[_]: Async]: GraphQL[F, StateService] = {
val (schema, um) = Federation.federate[StateService, Any, Json](
Schema(StateAPI.Query),
sangria.marshalling.circe.CirceInputUnmarshaller,
stateResolver)
GraphQL(schema, DeferredResolver.fetchers(StateGraphQLSchema.states), ctx.pure[F])(Async[F], um)
}
The stateResolver
delegates the resolution of the state entities to a Fetcher
,
allowing the state service to resolve the state entities based on the provided ids in one batch.
The GraphQL server uses the provided schema and unmarshaller as arguments for the sangria executor: implementation
-
The review service defines the
Review
type, which has a reference to theState
type. -
As
State
is implemented by the state service, we don't need to implement the whole state in the review service. Instead, for each entity implemented by another service, a stub type should be created (containing just the minimal information that will allow to reference the entity).implementation of the stub type State (notice the usage of the @external directive).
-
In the end, the same code used to federate the state service is used to federate the review service.
The federation router can expose the GraphQL endpoint, and resolve any GraphQL query using our sangria GraphQL services.
The sangria GraphQL services endpoints are configured in the supergraph configuration, used by rover to compose the supergraph:
federation_version: 2
subgraphs:
state:
schema:
subgraph_url: http://localhost:9081/api/graphql
review:
schema:
subgraph_url: http://localhost:9082/api/graphql
- This is a technology preview. We are actively working on it and cannot promise a stable API yet.
- It's highly recommended to use Deferred Value Resolution in the
EntityResolver
to batch the fetching of the entities. - The library upgrades the marshaller to map values scalars (e.g. json objects as scalars). This can lead to security issues as discussed here.
Contributions are warmly desired 🤗. Please follow the standard process of forking the repo and making PRs 🤓
sangria-federated is licensed under Apache License, Version 2.0.