This gem extends the GraphQL Ruby gem to add support for creating an Apollo Federation schema.
This gem is still in a beta stage and may have some bugs or incompatibilities. See the Known Issues and Limitations below. If you run into any problems, please file an issue.
Add this line to your application's Gemfile:
gem 'apollo-federation'
And then execute:
$ bundle
Or install it yourself as:
$ gem install apollo-federation
Include the ApolloFederation::Field
module in your base field class:
require 'apollo-federation'
class BaseField < GraphQL::Schema::Field
include ApolloFederation::Field
end
Include the ApolloFederation::Object
module in your base object class:
class BaseObject < GraphQL::Schema::Object
include ApolloFederation::Object
field_class BaseField
end
Include the ApolloFederation::Interface
module in your base interface module:
module BaseInterface
include GraphQL::Schema::Interface
include ApolloFederation::Interface
field_class BaseField
end
Finally, include the ApolloFederation::Schema
module in your schema:
class MySchema < GraphQL::Schema
include ApolloFederation::Schema
end
The example
folder contains a Ruby implementation of Apollo's federation-demo
. To run it locally, install the Ruby dependencies:
$ bundle
Install the Node dependencies:
$ yarn
Start all of the services:
$ yarn start-services
Start the gateway:
$ yarn start-gateway
This will start up the gateway and serve it at http://localhost:5000.
The API is designed to mimic the API of Apollo's federation library. It's best to read and understand the way federation works, in general, before attempting to use this library.
Call extend_type
within your class definition:
class User < BaseObject
extend_type
end
Call key
within your class definition:
class User < BaseObject
key fields: 'id'
end
Pass the external: true
option to your field definition:
class User < BaseObject
field :id, ID, null: false, external: true
end
Pass the requires:
option to your field definition:
class Product < BaseObject
field :price, Int, null: true, external: true
field :weight, Int, null: true, external: true
field :shipping_estimate, Int, null: true, requires: { fields: "price weight"}
end
Pass the provides:
option to your field definition:
class Review < BaseObject
field :author, 'User', null: true, provides: { fields: 'username' }
end
Define a resolve_reference
class method on your object. The method will be passed the reference from another service and the context for the query.
class User < BaseObject
def self.resolve_reference(reference, context)
USERS.find { |user| user[:id] == reference[:id] }
end
end
To support federated tracing:
- Add
use ApolloFederation::Tracing
to your schema class. - Change your controller to add
tracing_enabled: true
to the execution context based on the presence of the "include trace" header:def execute # ... context = { tracing_enabled: ApolloFederation::Tracing.should_add_traces(headers) } # ... end
- Change your controller to attach the traces to the response:
def execute # ... result = YourSchema.execute(query, ...) render json: ApolloFederation::Tracing.attach_trace_to_result(result) end
- Only works with class-based schemas, the legacy
.define
API will not be supported - Does not add directives to the output of
Schema.to_definition
. Sincegraphql-ruby
doesn't natively support schema directives, the directives will only be visible to the Apollo Gateway through theQuery._service
field (see the Apollo Federation specification)