Skip to main content

Documentation Index

Fetch the complete documentation index at: https://cosmo-docs.wundergraph.com/llms.txt

Use this file to discover all available pages before exploring further.

Definition

directive @composeDirective(name: String!) repeatable on SCHEMA

Arguments

ArgumentTypeDescription
nameString!The name of the imported directive (with leading @).

Overview

The @composeDirective directive declares that another (custom) directive should be propagated into the router schema (supergraph schema). By default, only specific machinery directives are persisted in the federated graph; custom directives are not.
The directive to be propagated into the router schema must first be imported through the @link directive. See the @link directive page for further details.

Usage

Behavior attempts to mirror that of Apollo. Warnings are added in certain cases to provide extra context and ensure the desired effect is reached.
Once the custom directive is imported through an @link directive, the custom directive definition must also be added to the subgraph schema importing that directive. Please note that composition cannot cross-reference or verify the definitions declared in the feature URL and the schema in any way. Lastly, the name of the imported and defined directive (with leading @) must be provided as a value to the name argument of a @composeDirective directive:
# subgraph 1
schema
@link(
  import: ["@myDirective"],
  url: "https://company.org/my-feature/myDirective/v1.0"
)
@composeDirective(name: "@myDirective") {
  query: Query
}

directive @myDirective on FIELD_DEFINITION

type Query {
    echo(string: String!): String! @myDirective
}
For brevity, “composing a directive” will henceforth serve as a substitute for “providing the name of an imported and defined directive to the name argument of a @composeDirective directive”.

Edge cases

Multiple versions

For each subgraph that composes a directive in that subgraph, only the definition with the highest version will be propagated into the router schema. For example:
# subgraph 1
schema
@link(
  import: ["@myDirective"],
  url: "https://company.org/my-feature/myDirective/v1.1"
)
@composeDirective(name: "@myDirective") {
  query: Query
}

directive @myDirective(input: String!, option: Int) repeatable on FIELD_DEFINITION

type Query @shareable {
    echo(string: String!): String! @myDirective(input: "a", option: 1)
}

# subgraph 2
schema
@link(
  import: ["@myDirective"],
  url: "https://company.org/my-feature/myDirective/v1.0"
)
@composeDirective(name: "@myDirective") {
  query: Query
}

directive @myDirective(input: String!) repeatable on FIELD_DEFINITION

type Query @shareable {
    echo(string: String!): String! @myDirective(input: "b")
}

# router schema
schema {
  query: Query
}

directive @myDirective(input: String! option: Int) on FIELD_DEFINITION

type Query {
    echo(string: String!): String! @myDirective(input: "a", option: 1) @myDirective(input: "b")
}

Non-propagation

If a directive is not referenced in at least one subgraph that also composes that directive, declarations of that directive will not be propagated into the router schema even if the directive is used in other subgraphs. The directive definition, however, will still be propagated:
# subgraph 1
schema
@link(
  import: ["@myDirective"],
  url: "https://company.org/my-feature/myDirective/v1.0"
)
@composeDirective(name: "@myDirective") {
  query: Query
}

directive @myDirective on FIELD_DEFINITION

type Query @shareable {
    echo(string: String!): String!
}

# subgraph 2
schema {
  query: Query
}

directive @myDirective on FIELD_DEFINITION

type Query @shareable {
    echo(string: String!): String! @myDirective
}

# router schema
schema {
  query: Query
}

directive @myDirective(input: String!) on FIELD_DEFINITION

type Query {
    echo(string: String!): String!
}

Directive de-duplication

If a composed directive is declared on the same coordinates across subgraphs, only unique declarations will be propagated. This behaviour is regardless of whether the directive definition is repeatable:
# subgraph 1
schema
@link(
  import: ["@myDirective"],
  url: "https://company.org/my-feature/myDirective/v1.0"
)
@composeDirective(name: "@myDirective") {
  query: Query
}

directive @myDirective(input: String!) repeatable on FIELD_DEFINITION

type Query @shareable {
    echo(string: String!): String! @myDirective(input: "a")
}

# subgraph 2
schema
@link(import: ["@myDirective"], url: "https://company.org/my-feature/myDirective/v1.0")
@composeDirective(name: "@myDirective") {
  query: Query
}

directive @myDirective(input: String!) repeatable on FIELD_DEFINITION

type Query @shareable {
    echo(string: String!): String! @myDirective(input: "a")
}

# router schema
schema {
  query: Query
}

directive @myDirective(input: String!) repeatable on FIELD_DEFINITION

type Query {
    "note that the directive with argument value 'a' appears once"
    echo(string: String!): String! @myDirective(input: "a")
}

Multiple unique directive declarations with a non-repeatable definition

If the highest version of the directive is not defined as repeatable, but the directive is declared on a node in multiple subgraphs with disparate arguments (where applicable), only the first encountered instance of the directive will be propagated into the router schema for that node. This behaviour will also produce a warning. For example:
# subgraph 1
schema
@link(
  import: ["@myDirective"],
  url: "https://company.org/my-feature/myDirective/v1.1"
)
@composeDirective(name: "@myDirective") {
  query: Query
}

directive @myDirective(input: String!) on FIELD_DEFINITION

type Query @shareable {
    echo(string: String!): String! @myDirective(input: "a")
}

# subgraph 2
schema
@link(
  import: ["@myDirective"],
  url: "https://company.org/my-feature/myDirective/v1.0"
)
@composeDirective(name: "@myDirective") {
  query: Query
}

directive @myDirective(input: String!) repeatable on FIELD_DEFINITION

type Query @shareable {
    echo(string: String!): String! @myDirective(input: "b")
}

# router schema
schema {
  query: Query
}

directive @myDirective(input: String!) on FIELD_DEFINITION

type Query {
    "note that the directive with argument value 'b' does not propagate"
    echo(string: String!): String! @myDirective(input: "a")
}

Incompatible inter-subgraph definitions

Upon federation, all declarations of a composed directive will be validated against the definition of the composed directive with the highest version. This means a directive that is valid in subgraph may no longer be valid in the router schema. Such cases produce a composition error:
# subgraph 1
schema
@link(
  import: ["@myDirective"],
  url: "https://company.org/my-feature/myDirective/v1.1"
)
@composeDirective(name: "@myDirective") {
  query: Query
}

directive @myDirective repeatable on FIELD_DEFINITION

type Query @shareable {
    echo(string: String!): String! @myDirective
}

# subgraph 2
schema
@link(
  import: ["@myDirective"],
  url: "https://company.org/my-feature/myDirective/v1.0"
)
@composeDirective(name: "@myDirective") {
  query: Query
}

directive @myDirective(input: String!) repeatable on FIELD_DEFINITION

type Query @shareable {
    echo(string: String!): String! @myDirective(input: "b")
}

Errors

@composeDirective will produce composition errors if:
  • The directive name supplied to the name argument is not imported through a @link directive.
  • The string supplied to the name argument does not start with @.
  • The user attempts to provide a federation directive (e.g., @key) as an argument.
  • Directive declarations are incompatible across subgraphs.