It’s definitely possible to conditionally exclude fields using a custom directive, but the implementation differs slightly depending on whether you’re using a monolithic GraphQL server or an GraphQL Federation architecture. Since you didn’t specify your setup, I’ll cover both cases.
Monolithic GraphQL Server
In a monolithic setup, you can create a custom directive (e.g., @exclude
) to remove fields based on an environment variable. Use @graphql-tools/schema
to transform the schema and return null for fields that should be excluded.
directive @exclude(for: Client!) on FIELD_DEFINITION
enum Client {
CLIENT_1
CLIENT_2
}
type Foo {
bar: String!
baz: String! @exclude(for: CLIENT_1)
}
type Query {
foo: Foo!
}
GraphQL Federation
In a Federation setup, the process is similar, but there’s a catch: the Router uses the _service { sdl }
query to compose the supergraph
schema, not the __schema
introspection. If you apply a directive transformation using buildSubgraphSchema
, the transformed schema (with fields removed) is reflected in the subgraph’s introspection (__schema
), but the schema sent to the router (_service { sdl }
) won’t include these changes.
Additionally, makeExecutableSchema
doesn’t recognize Federation directives like @link
, @key
, etc., which causes errors. To fix this, you need to:
- Explicitly declare Federation directives in your schema.
- Apply the directive transformation before passing the schema to
buildSubgraphSchema
.
I’m not sure, but maybe you can solve this problem in Federation using @tag
directive and Managed Federation
If you are using Federation and have one server for each client, consequently, one router for each, you could use the @inaccessible
directive, it’s much easier than the previous one. But if you need to exclude a specific field based on environment variable during the startup, this directive will not help you.
EDIT: I’m not sure, but maybe you can use the @exclude directive to add the @inaccessible directive to the field if condition is true instead of return null