Apollo Federation
"Implement a single data graph across multiple services"
Scope
Tanka GraphQL implements the service section of the Apollo Federation specification allowing GraphQL service implemented using it to be joined into graph managed by Gateway.
Installation
Support is provided as an NuGet package.
dotnet add package Tanka.GraphQL.Extensions.ApolloFederation
Usage
Creating a service requires two steps:
- Define entities in service schema
- Create federation service from schema
First step is achived by extending the schema with federation directives which allow you to define your entities.
Extending is done by first adding the directives to schema using AddFederationDirectives
SchemaBuilder
extension
method. Use @key
directive to mark object or interface as an entity and specify key fields.
Second step is after you have your basic schema with entities specified and it will add the required extension points to schema, mainly additional fields to query root type.
Example
public static ISchema Create()
{
var builder = new SchemaBuilder()
.AddFederationDirectives();
var typeDefs = @"
type Review @key(fields: ""id"") {
id: ID!
body: String
author: User @provides(fields: ""username"")
product: Product
}
type User @key(fields: ""id"") @extends {
id: ID! @external
username: String @external
reviews: [Review]
}
type Product @key(fields: ""upc"") @extends {
upc: String! @external
reviews: [Review]
}
type Query {
}
";
builder.Sdl(typeDefs);
builder.UseResolversAndSubscribers(
new ObjectTypeMap
{
["User"] = new FieldResolversMap
{
{"id", Resolve.PropertyOf<User>(u => u.ID)},
{"username", UserUsername},
{"reviews", UserReviews}
},
["Review"] = new FieldResolversMap
{
{"id", Resolve.PropertyOf<Review>(r => r.ID)},
{"body", Resolve.PropertyOf<Review>(r => r.Body)},
{"author", ReviewAuthor},
{"product", Resolve.PropertyOf<Review>(r => r.Product)}
},
["Product"] = new FieldResolversMap
{
{"upc", Resolve.PropertyOf<Product>(p => p.Upc)},
{"reviews", ProductReviews}
}
});
var schema = builder.Build();
// create federated service from builder and add
// reference resolvers
var federationBuilder = Federation.ServiceFrom(
schema,
new DictionaryReferenceResolversMap
{
["User"] = UserReference,
["Product"] = ProductReference
});
return SchemaTools.MakeExecutableSchemaWithIntrospection(federationBuilder);
}
Demo
Demo is provided as an fork of the federation demo. It's modified to use Tanka.GraphQL.Dev.Reviews project as an replacement for reviews service.
git clone https://github.com/pekkah/tanka-graphql.git
cd tanka-graphql/dev/GraphQL.Dev.Reviews
dotnet run
git clone https://github.com/pekkah/federation-demo.git
cd federation-demo
git switch tanka-graphql-reviews-service
npm run start-services
# in a yet another prompt
npm run start-gateway
# open http://localhost:4000 in your browser to test the service