Federation
Gateway schema extensions
How to connect federated types
A common use case may be to extend a certain type of a federated service with values resolved by another service. The only place to extend the schema likewise, is the gateway itself. Let's stay with our example. We have one service that is connected to an eDirectory and one connected to an Active Directory. That means we have the types User
(eDirectory) and AD_User
(Active Directory). We want to extend the User
type by a property adUser
that resolves the connected user from the Active Directory. As well we want to extend the AD_User
type by the property edirUser
vice versa.
For our example to work, there must be some way to align both user types via certain properties. In our case the eDirectory service may have its User
type with a adObjectSid
and the Active Directory service has extended the AD_User
type with the property objectSid
. Also they both extended the filter inputs to be able to filter by those new properties:
eDirectory schema extension:
extend type User {
adObjectSid: String @ldapField(attribute: "adObjectSid")
}
extend input UserBy {
adObjectSid: [String!]
}
extend input UserWhere {
adObjectSid: [String!]
}
Active Directory schema extension:
extend type AD_User {
objectSid: String @ldapField(attribute: "objectSid") @buffer(format: "objectSid")
}
extend input AD_UserBy {
objectSid: [String!]
}
extend input AD_UserWhere {
objectSid: [String!]
}
Pay attention to the @buffer
directive and the passed format objectSid
. This format was added tom the @buffer directive in version v9.5.0 as well and returns the string representation of an Active Directory objectSid.
The @graphql directive
The IdentityHub as a gateway has no access to the usual directives (@ldapField, @ldapSearch, etc). It has though one new directive called @graphql
. Have a look to this gateway schema extension:
extend type User {
adUser: AD_User
@graphql(query: "($id: [ID!]){user(by: {id: $id}) { adObjectSid }}", variables: {id: "id"})
@graphql(query: "($objectSid: [String!]){AD_user(by: {objectSid: $objectSid}) {[...]}}", variables: {objectSid: "user.adObjectSid"}, path: "AD_user")
}
extend type AD_User {
edirUser: User
@graphql(query: "($id: [ID!]){AD_user(by: {id: $id}) { objectSid }}", variables: {id: "id"})
@graphql(query: "($objectSid: [String!]){user(by: {adObjectSid: $objectSid}) {[...]}}", variables: {objectSid: "AD_user.objectSid"}, path: "user")
}
As you can see this directive is repeatable
and can be chained to achieve a certain goal. The parameters are the query
, the variables
and a path
.
At first we have a look at the adUser
extension. The first @graphql
directive is querying (user(){}
) the user itself (the parent object) by using the id
of the parent User object. The directive ensures that the id
is requested even if it is not in gthe selection set of the prent user. As you can see the selection set of our @graphql query contains the adObjectSid
. The result of that first directive would be:
{
user: {
adObjectSid: "some SID"
}
}
This result is passed as new parent
object to the next @graphql
directive. Now we can use the user.adObjectSid
in our variables to send a query AD_user
and filter by the objectSid
. The path
property defined what the directive should resolve starting from the content of the data
property. Since we want to resolve an AD_User
we pass the path AD_user
which correlates to the query name.
As you can see we used [...]
as selection set in the second directive query. This is a placeholder that gets replaced with the really requested selection set. A query utilizing the shown schema extension could be:
query edirUser {
user(by: {id: "xyz"}) {
dn
fullName
adUser {
name
mail
company
}
}
}
In our example [...]
would be replaced with the really selected fields name
, mail
and company
.
The second schema extension does the same vice versa.
Every query send via the @graphql
directive can be named, i.e.
@graphql(query: "query namedQuery { user(...) { ... } }")
If it is not, it will get a unique name based on the parent type name, the field name and a hash of the query itself.