Package detail

@theguild/federation-composition

graphql-hive197.6kMIT0.18.5

Open Source Composition library for Apollo Federation

graphql, federation, graphql-federation

readme

Federation Composition

Supports all Federation versions. Drop-in replacement for @apollo/composition.

🚧 Work in progress, so please check TODOs.

Comparison with @apollo/composition

  • Open Source (MIT License)
  • identical API
  • same set of validation rules and exact same error messages
  • produces Supergraph SDL (can be used with Apollo Router and every tool that supports Supergraph SDL)
  • does not support Hints
  • 3-4x faster
  • up to 2x less memory usage

Installation

# NPM
npm install @theguild/federation-composition
# PNPM
pnpm add @theguild/federation-composition
# Yarn
yarn add @theguild/federation-composition

Usage

import { parse } from "graphql";
import {
  composeServices,
  compositionHasErrors,
} from "@theguild/federation-composition";

const result = composeServices([
  {
    name: "users",
    typeDefs: parse(/* GraphQL */ `
      extend schema
        @link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@key"])

      type User @key(fields: "id") {
        id: ID!
        name: String!
      }

      type Query {
        users: [User]
      }
    `),
  },
  {
    name: "comments",
    typeDefs: parse(/* GraphQL */ `
      extend schema
        @link(
          url: "https://specs.apollo.dev/federation/v2.3"
          import: ["@key", "@external"]
        )

      extend type User @key(fields: "id") {
        id: ID! @external
        comments: [Comment]
      }

      type Comment {
        id: ID!
        text: String!
        author: User!
      }
    `),
  },
]);

if (compositionHasErrors(result)) {
  console.error(result.errors);
} else {
  console.log(result.supergraphSdl);
}

Contributing

Install the dependencies:

pnpm install

Run the tests:

pnpm test

How to help?

  • Grab one of the failing tests and fix it.
  • Add new tests to cover more cases.
  • Add missing rules.
  • Look for // TODO: comments in the code and fix/implement them.
  • Todos with // TODO: T[NUMBER] are on Notion.
  • Look for skipIf or skip in the tests.
  • Refactor code (piece by piece) if you feel like it.

Compatibility

The lack of a publicly available specification for Apollo Federation, coupled with the non open-source license of the Apollo Composition library, makes it difficult or even impossible to assure complete compatibility of our open-source composition library.

Given that Apollo tools utilize their composition library, there is a potential for conflicting results between our composition library and Apollo's. This may lead to variations in the supergraph, differing composition errors, or, in some cases, conflicting composition outcomes.

We are working to ensure that our composition library is as compatible as possible with Apollo's and will continue to do so as we learn more about the Federation specification.

Your feedback and bug reports are welcome and appreciated.

Supergraph SDL Composition

✅ Done

Validation

🚧 Work in progress

Validation rules

  • NO_QUERIES
  • TYPE_KIND_MISMATCH
  • EXTENSION_WITH_NO_BASE
  • FIELD_TYPE_MISMATCH
  • FIELD_ARGUMENT_TYPE_MISMATCH
  • EXTERNAL_TYPE_MISMATCH
  • ENUM_VALUE_MISMATCH
  • EMPTY_MERGED_ENUM_TYPE
  • EMPTY_MERGED_INPUT_TYPE
  • OVERRIDE_SOURCE_HAS_OVERRIDE
  • EXTERNAL_MISSING_ON_BASE
  • REQUIRED_ARGUMENT_MISSING_IN_SOME_SUBGRAPH
  • REQUIRED_INPUT_FIELD_MISSING_IN_SOME_SUBGRAPH
  • EXTERNAL_ARGUMENT_MISSING
  • INPUT_FIELD_DEFAULT_MISMATCH
  • FIELD_ARGUMENT_DEFAULT_MISMATCH
  • DEFAULT_VALUE_USES_INACCESSIBLE
  • ONLY_INACCESSIBLE_CHILDREN
  • REFERENCED_INACCESSIBLE
  • INTERFACE_KEY_MISSING_IMPLEMENTATION_TYPE
  • INVALID_FIELD_SHARING
  • PROVIDES_INVALID_FIELDS_TYPE
  • INVALID_GRAPHQL
  • OVERRIDE_ON_INTERFACE
  • OVERRIDE_FROM_SELF_ERROR
  • QUERY_ROOT_TYPE_INACCESSIBLE
  • PROVIDES_UNSUPPORTED_ON_INTERFACE
  • REQUIRES_UNSUPPORTED_ON_INTERFACE
  • KEY_UNSUPPORTED_ON_INTERFACE
  • KEY_INVALID_FIELDS_TYPE
  • KEY_FIELDS_HAS_ARGS
  • KEY_FIELDS_SELECT_INVALID_TYPE
  • KEY_INVALID_FIELDS
  • REQUIRES_INVALID_FIELDS
  • REQUIRES_INVALID_FIELDS_TYPE
  • MERGED_DIRECTIVE_APPLICATION_ON_EXTERNAL
  • INTERFACE_KEY_NOT_ON_IMPLEMENTATION
  • PROVIDES_FIELDS_MISSING_EXTERNAL
  • REQUIRES_FIELDS_MISSING_EXTERNAL
  • PROVIDES_ON_NON_OBJECT_FIELD
  • INVALID_SUBGRAPH_NAME
  • PROVIDES_FIELDS_HAS_ARGS
  • PROVIDES_INVALID_FIELDS
  • EXTERNAL_UNUSED
  • DIRECTIVE_COMPOSITION_ERROR
  • ROOT_QUERY_USED
  • ROOT_MUTATION_USED
  • ROOT_SUBSCRIPTION_USED
  • INVALID_SHAREABLE_USAGE
  • DIRECTIVE_DEFINITION_INVALID
  • KEY_DIRECTIVE_IN_FIELDS_ARG
  • PROVIDES_DIRECTIVE_IN_FIELDS_ARG
  • REQUIRES_DIRECTIVE_IN_FIELDS_ARG
  • TYPE_DEFINITION_INVALID
  • OVERRIDE_COLLISION_WITH_ANOTHER_DIRECTIVE
  • INTERFACE_OBJECT_USAGE_ERROR
  • REQUIRED_INACCESSIBLE
  • SATISFIABILITY_ERROR
  • INTERFACE_FIELD_NO_IMPLEM
  • LINK_IMPORT_NAME_MISMATCH
  • IMPLEMENTED_BY_INACCESSIBLE

TODOs

  • [ ] DISALLOWED_INACCESSIBLE
  • [ ] EXTERNAL_ARGUMENT_DEFAULT_MISMATCH
  • [ ] EXTERNAL_ARGUMENT_TYPE_MISMATCH
  • [ ] EXTERNAL_COLLISION_WITH_ANOTHER_DIRECTIVE
  • [ ] UNSUPPORTED_LINKED_FEATURE
  • [ ] TYPE_WITH_ONLY_UNUSED_EXTERNAL

changelog

@theguild/federation-composition

0.18.5

Patch Changes

  • #151 f9b9908 Thanks @n1ru4l! - Fix issue where the satisfiability check raised an exception for fields that share different object type and interface definitions across subgraphs.

  • #152 e4440a1 Thanks @n1ru4l! - Fix issue where scalar type marked with @inaccessible does not fail the composition if all usages are not marked with @inaccessible.

    Composing the following subgraphs resulted in an invalid supergraph instead of failing the composition.

    # Subgraph A
    extend schema
      @link(
        url: "https://specs.apollo.dev/federation/v2.9"
        import: ["@inaccessible"]
      )
    
    type Query {
      a: Foo
    }
    
    scalar Foo
    
    # Subgraph B
    extend schema
      @link(
        url: "https://specs.apollo.dev/federation/v2.9"
        import: ["@inaccessible"]
      )
    
    type Query {
      b: String
    }
    
    scalar Foo @inaccessible
    

    Now it correctly raises a composition error with the message Type "Foo" is @inaccessible but is referenced by "Query.a", which is in the API schema..

0.18.4

Patch Changes

  • #146 55b48e9 Thanks @n1ru4l! - Resolve usage of @requires FieldSet with a union field selection to raise an EXTERNAL_UNUSED error.

  • #150 9bd8016 Thanks @n1ru4l! - Fix incorrectly raised IMPLEMENTED_BY_INACCESSIBLE error for inaccessible object fields where the object type is inaccessible.

    For example the following subgraph, will no longer result in the error Field B.id is @inaccessible but implements the interface field Node.id, which is in the API schema..

    schema
      @link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@tag"]) {
      query: Query
    }
    
    type Query {
      b(id: ID! @federation__inaccessible): B @federation__inaccessible
      a(id: ID!): A
    }
    
    type B implements Node @federation__inaccessible {
      id: ID! @federation__inaccessible
    }
    
    type A implements Node {
      id: ID!
    }
    
    interface Node {
      id: ID!
    }
    
  • #147 8c5bc0c Thanks @n1ru4l! - Add support for @provides fragment selection sets on union type fields.

    type Query {
      media: [Media] @shareable @provides(fields: "... on Book { title }")
    }
    union Media = Book | Movie
    

0.18.3

Patch Changes

  • #143 bcea968 Thanks @n1ru4l! - Do not throw an error when encountering invalid usage of @tag directive within subgraphs.

0.18.2

Patch Changes

  • #141 fdb491f Thanks @ardatan! - Fixes the issue where the composition gives errors in case of the following:

    extend schema
      @link(
        url: "https://specs.apollo.dev/federation/v2.7"
        import: ["@key", "@composeDirective"]
      )
      @link(url: "https://myspecs.dev/myDirective/v1.0", import: ["@myDirective"])
      @composeDirective(name: "@myDirective")
    
    directive @myDirective(myarg: [MyEnum!]!) on OBJECT # A directive with a non-nullable list argument of non-nullable enums
    enum MyEnum {
      MY_ENUM_VALUE
    }
    type Query {
      myRootField: MyObject
    }
    
    type MyObject @myDirective(myarg: []) {
      myField: String
    }
    

0.18.1

Patch Changes

0.18.0

Minor Changes

  • Support progressive overrides (@override(label: "<value>"))

Patch Changes

  • Performance improvements (lazy compute of errors), especially noticeable in large schemas (2s -> 600ms)

0.17.0

Minor Changes

  • Allow to use @composeDirective on a built-in scalar (like @oneOf)

0.16.0

Minor Changes

  • Allow to use v2.7, but not progressive @override labels
  • Allow to use v2.8, but not @context and @fromContext directives
  • Support @cost and @listSize directives
  • Add extractLinkImplementations function to extract information about applied specs (@link)

Patch Changes

  • Reuse type and direcive definitions from the composition logic to detect a supergraph spec in an SDL or transform a supergraph to a public schema

0.15.0

Minor Changes

  • Implement rule for IMPLEMENTED_BY_INACCESSIBLE error code.

0.14.5

Patch Changes

  • #87 9c26af9 Thanks @n1ru4l! - Do not raise DEFAULT_VALUE_USES_INACCESSIBLE for inaccessible default value on inaccessible field.

0.14.4

Patch Changes

  • #82 7d640bf Thanks @kamilkisiela! - Fix a child data type field not being accessible via interfaceObject

  • #81 ded4b47 Thanks @ardatan! - Respect inaccessible enum values while creating the public schema from the supergraph AST

0.14.3

Patch Changes

  • #78 4e25e6d Thanks @kamilkisiela! - transformSupergraphToPublicSchema removes now @policy, @requiresScopes and @authenticated

0.14.2

Patch Changes

  • #76 a3cb724 Thanks @kamilkisiela! - Fix a missing @join__field on a query field where @override is used, but not in all subgraphs.

0.14.1

Patch Changes

  • #74 7456d14 Thanks @kamilkisiela! - Show TYPE_KIND_MISMATCH and ignore INTERFACE_FIELD_NO_IMPLEM when there is a type kind mismatch

0.14.0

Minor Changes

0.13.0

Minor Changes

0.12.1

Patch Changes

  • #68 51dd57a Thanks @kamilkisiela! - Unknown types are now always reported as GraphQLError (previously in some logic paths, it was an exception).

0.12.0

Minor Changes

0.11.4

Patch Changes

0.11.3

Patch Changes

  • #62 e50bc90 Thanks @kamilkisiela! - Fix: do not expose federation__Scope and federation__Policy scalar definitions to a supergraph

0.11.2

Patch Changes

  • #60 2f7fef1 Thanks @kamilkisiela! - Normalize enum values to be printed as enum values in Supergraph SDL, even if the user's subgraph schema has them as strings

0.11.1

Patch Changes

0.11.0

Minor Changes

Patch Changes

0.10.1

Patch Changes

0.10.0

Minor Changes

Patch Changes

0.9.0

Minor Changes

0.8.2

Patch Changes

  • #46 cfa9950 Thanks @kamilkisiela! - Add requiresScopes__Scope and policy__Policy to transformSupergraphToPublicSchema

  • #44 de983b0 Thanks @kamilkisiela! - Add containsSupergraphSpec to detect if Supergraph related scalars, enums or directives are used

0.8.1

Patch Changes

  • #42 f858c3f Thanks @n1ru4l! - Fix REQUIRED_INACCESSIBLE occurring on inaccessible fields/input types

0.8.0

Minor Changes

  • #40 4cba351 Thanks @n1ru4l! - Implement validation rules for REQUIRED_INACCESSIBLE for input types and field arguments.

0.7.1

Patch Changes

  • #36 fdba937 Thanks @kamilkisiela! - Visit every field in provides and requires directives

  • #36 fdba937 Thanks @kamilkisiela! - Fix unnecessary join__field(override:) on Query fields when it points to non-existing subgraph

  • #36 fdba937 Thanks @kamilkisiela! - Deduplicate composed directives

  • #39 e77eb2c Thanks @n1ru4l! - Ignore inaccessible field arguments within the DEFAULT_VALUE_USES_INACCESSIBLE rule.

    Fixes an issue where an inaccessible field argument uses a default value that is inaccessible would cause a false error.

    type User @key(fields: "id") {
      id: ID
      friends(type: FriendType = FAMILY @inaccessible): [User!]!
    }
    
    enum FriendType {
      FAMILY @inaccessible
      FRIEND
    }
    
  • #36 fdba937 Thanks @kamilkisiela! - Remove duplicated link spec definitions

  • #36 fdba937 Thanks @kamilkisiela! - Drop unused fields marked with @external only in a single type in Fed v1

  • 220dfc0 Thanks @kamilkisiela! - Fix missing usedOverridden on non-external key field

0.7.0

Minor Changes

Patch Changes

0.6.2

Patch Changes

  • 1ddf34e Thanks @kamilkisiela! - Fix EXTERNAL_ARGUMENT_MISSING - include nullable arguments as well

  • 1ddf34e Thanks @kamilkisiela! - Merge type definitions and type extensions when validating fields used in @requires, @provides and @key

  • 2525a24 Thanks @kamilkisiela! - Support [T!]! type in @key(fields), @provides(fields) and @requires(fields)

0.6.1

Patch Changes

0.6.0

Minor Changes

Patch Changes

0.5.0

Minor Changes

0.4.0

Minor Changes

Patch Changes

0.3.0

Minor Changes

  • #23 2d72e03 Thanks @kamilkisiela! - Add sortSDL function to sort DocumentNode (type system definitions and extensions)

0.2.0

Minor Changes

  • #21 443283e Thanks @n1ru4l! - Remove stripFederationFromSupergraph in favor of transformSupergraphToPublicSchema.

    Instead of stripping only federation specific types, transformSupergraphToPublicSchema yields the public api schema as served by the gateway.

0.1.4

Patch Changes

  • #19 e0ef0bb Thanks @kamilkisiela! - Make stripFederationFromSupergraph less strict and remove only Federation directives

0.1.3

Patch Changes

0.1.2

Patch Changes

0.1.1

Patch Changes

0.1.0

Minor Changes

0.0.0

Minor Changes

Patch Changes