From f4ca1862fd2e9a8bb467bad6a093038d193bf194 Mon Sep 17 00:00:00 2001 From: Greg MacWilliam Date: Fri, 31 May 2024 08:59:04 -0400 Subject: [PATCH] update documentation. --- README.md | 4 +-- docs/mechanics.md | 42 +++++++++++++++++++++++ test/graphql/stitching/supergraph_test.rb | 21 ------------ 3 files changed, 44 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 12acaac3..2888dd5a 100644 --- a/README.md +++ b/README.md @@ -153,7 +153,7 @@ type Query { * The `@stitch` directive is applied to a root query where the merged type may be accessed. The merged type identity is inferred from the field return. * The `key: "id"` parameter indicates that an `{ id }` must be selected from prior locations so it may be submitted as an argument to this query. The query argument used to send the key is inferred when possible ([more on arguments](#multiple-query-arguments) later). -Each location that provides a unique variant of a type must provide at least one resolver query for the type. The exception to this requirement are [foreign key types](./docs/mechanics.md##modeling-foreign-keys-for-stitching) that contain only a single key field: +Each location that provides a unique variant of a type must provide at least one resolver query for the type. The exception to this requirement are [outbound-only types](./docs/mechanics.md#outbound-only-merged-types) and/or [foreign key types](./docs/mechanics.md##modeling-foreign-keys-for-stitching) that contain no exclusive data: ```graphql type Product { @@ -161,7 +161,7 @@ type Product { } ``` -The above representation of a `Product` type provides no unique data beyond a key that is available in other locations. Thus, this representation will never require an inbound request to fetch it, and its resolver query may be omitted. +The above representation of a `Product` type contains nothing but a key that is available in other locations. Therefore, this representation will never require an inbound request to fetch it, and its resolver query may be omitted. #### List queries diff --git a/docs/mechanics.md b/docs/mechanics.md index 35db9ef5..76420e17 100644 --- a/docs/mechanics.md +++ b/docs/mechanics.md @@ -303,3 +303,45 @@ And produces this result: ``` Location B is allowed to return `null` here because its one unique field, `rating`, is nullable (the `id` field can be provided by Location A). If `rating` were non-null, then null bubbling would invalidate the response data. + +### Outbound-only merged types + +Merged types do not always require a resolver query. For example: + +```graphql +# -- Location A + +type Widget { + id: ID! + name: String +} + +type Query { + widgetA(id: ID!): Widget @stitch(key: "id") +} + +# -- Location B + +type Widget { + id: ID! + size: Float +} + +type Query { + widgetB(id: ID!): Widget @stitch(key: "id") +} + +# -- Location C + +type Widget { + id: ID! + name: String + size: Float +} + +type Query { + featuredWidget: Widget +} +``` + +In this graph, `Widget` is a merged type without a resolver query in location C. This works because all of its fields are resolvable in other locations; that means location C can provide outbound representations of this type without ever needing to resolve inbound requests for it. Outbound types do still require a key field (such as `id` above) that allow them to join with data in other resolver locations. diff --git a/test/graphql/stitching/supergraph_test.rb b/test/graphql/stitching/supergraph_test.rb index 2be77264..b25cd7f6 100644 --- a/test/graphql/stitching/supergraph_test.rb +++ b/test/graphql/stitching/supergraph_test.rb @@ -290,27 +290,6 @@ def test_route_type_to_locations_favors_longer_paths_through_necessary_locations assert routes.none? { |_key, path| path.any? { _1["location"] == "e" } } end - # def test_route_type_to_locations_returns_nil_for_unreachable_locations - # a = %| - # type T { upc:ID! } - # type Query { a(upc:ID!):T @stitch(key: "upc") } - # | - # b = %| - # type T { id:ID! } - # type Query { b(id:ID!):T @stitch(key: "id") } - # | - # c = %| - # type T { id:ID! } - # type Query { c(id:ID!):T @stitch(key: "id") } - # | - - # supergraph = compose_definitions({ "a" => a, "b" => b, "c" => c }) - - # routes = supergraph.route_type_to_locations("T", "b", ["a", "c"]) - # assert_equal ["c"], routes["c"].map { _1["location"] } - # assert_nil routes["a"] - # end - describe "#to_definition / #from_definition" do def setup alpha = %|