From 9bf53a006460d99974c113ee8e02d444fc6870a1 Mon Sep 17 00:00:00 2001 From: meskill <8974488+meskill@users.noreply.github.com> Date: Wed, 25 Sep 2024 13:38:50 +0000 Subject: [PATCH 1/4] feat: add federation subgraph doc --- docs/apollo-federation-subgraph.md | 92 ++++++++++++++++++++++++++++++ sidebars.ts | 2 +- 2 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 docs/apollo-federation-subgraph.md diff --git a/docs/apollo-federation-subgraph.md b/docs/apollo-federation-subgraph.md new file mode 100644 index 0000000000..8da4e843e8 --- /dev/null +++ b/docs/apollo-federation-subgraph.md @@ -0,0 +1,92 @@ +--- +title: Use Tailcall service as a Federation Subgraph +description: "Learn how to configure Tailcall to function as an Apollo Federation Subgraph, enabling seamless integration into a federated GraphQL environment." +slug: integrate-apollo-federation-graphql-tailcall-subgraph +sidebar_label: Apollo Federation Subgraph +--- + +This guide shows how to configure tailcall to function as an [Apollo Federation Subgraph](https://www.apollographql.com/docs/federation/building-supergraphs/subgraphs-overview/) in your GraphQL infrastructure. + +## Create the Tailcall config + +First, you need to create a basic Tailcall configuration. For reference, check out our [Getting Started](./getting-started.mdx) guide. + +## Define Entity Resolvers + +Now you need to add [entity resolvers](https://www.apollographql.com/docs/federation/entities/) to the Tailcall config to make it act as a subgraph. + +To do this, you need to define resolver on types by using one of the [directives](./configuration.mdx) that resolve the data. Use [`{{.value}}`](https://tailcall.run/docs/graphql-resolver-context-tailcall/#value) to access the fields that act as a federation `@key` and will be provided by the Federation Router when making the request to this subgraph. + +```graphql +type Post @http(path: "/posts", query: [{key: "id", value: "{{.value.id}}"}]) { + id: Int! + userId: Int! + title: String! + body: String! +} +``` + +:::note +Please, note that you don't need to specify the `@key` directive manually when defining entity resolver with Tailcall. It's because Tailcall can automatically infer the key definitions from the usage of the resolver itself. +::: + +## Register your subgraph + +Registration of the subgraph depends on what Federation Router you use. + +### GraphOS Router + +For the **GraphOS Router** please refer to the [GraphOS documentation](https://www.apollographql.com/docs/graphos/quickstart/cloud). Please note that currently, to fetch subgraph schema from Tailcall instance, you need to use introspection request with the Rover cli instead of providing the Tailcall config as the subgraph schema. + +When developing locally, use [Rover CLI](https://www.apollographql.com/docs/rover/) to start the development environment: + +1. Start the tailcall server as usual with `tailcall start`. +2. Register the subgraph using introspection with `rover dev --url http://localhost:8001/graphql --name post`. +3. Go to `http://localhost:4000` to inspect the router schema. + +### @apollo/gateway + +When using [`@apollo/gateway`](https://www.apollographql.com/docs/apollo-server/using-federation/api/apollo-gateway/) package, you need to specify the URLs to your subgraphs in order to register them. + +Example of `@apollo/gateway` configuration: + +```ts +import {ApolloServer} from "@apollo/server" +import {startStandaloneServer} from "@apollo/server/standalone" +import {ApolloGateway, IntrospectAndCompose} from "@apollo/gateway" + +const gateway = new ApolloGateway({ + supergraphSdl: new IntrospectAndCompose({ + subgraphs: [ + {name: "post", url: "http://localhost:8001/graphql"}, + {name: "user", url: "http://localhost:8002/graphql"}, + ], + }), +}) + +const server = new ApolloServer({ + gateway, + introspection: true, +}) + +const {url} = await startStandaloneServer(server) +console.log(`🚀 Server ready at ${url}`) +``` + +## Using federation specific directives + +The Federation specification defines [multiple directives](https://www.apollographql.com/docs/federation/federated-schemas/federated-directives) that control how the data is resolved. While the `@key` directive is not necessary to be specified, any other directives should be specified the same way as in any other federation subgraph schema. + +Example of using federation directives in the Tailcall config: + +```graphql +type User @http(path: "/users/{{.args.id}}") @shareable { + id: Int! + name: String! +} + +type Post @expr(body: {id: "{{.value.id}}", title: "post-title-{{.value.id}}"}) { + id: Int! + title: String! @override(from: "name") +} +``` diff --git a/sidebars.ts b/sidebars.ts index 362a8178de..7f56f70eac 100644 --- a/sidebars.ts +++ b/sidebars.ts @@ -47,7 +47,7 @@ const sidebars: SidebarsConfig = { "config-generation", ], }, - {type: "category", label: "Integrations", items: ["apollo-studio", "data-dog", "new-relic", "honey-comb", "llm"]}, + {type: "category", label: "Integrations", items: ["apollo-studio", "apollo-federation-subgraph", "data-dog", "new-relic", "honey-comb", "llm"]}, { type: "category", label: "Production", From 32de14bd48f0a0d0b905043839557f9f1861d589 Mon Sep 17 00:00:00 2001 From: meskill <8974488+meskill@users.noreply.github.com> Date: Wed, 25 Sep 2024 13:45:05 +0000 Subject: [PATCH 2/4] fix lint --- docs/apollo-federation-subgraph.md | 19 ++++++++++++++++--- sidebars.ts | 6 +++++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/docs/apollo-federation-subgraph.md b/docs/apollo-federation-subgraph.md index 8da4e843e8..833931cc76 100644 --- a/docs/apollo-federation-subgraph.md +++ b/docs/apollo-federation-subgraph.md @@ -18,7 +18,11 @@ Now you need to add [entity resolvers](https://www.apollographql.com/docs/federa To do this, you need to define resolver on types by using one of the [directives](./configuration.mdx) that resolve the data. Use [`{{.value}}`](https://tailcall.run/docs/graphql-resolver-context-tailcall/#value) to access the fields that act as a federation `@key` and will be provided by the Federation Router when making the request to this subgraph. ```graphql -type Post @http(path: "/posts", query: [{key: "id", value: "{{.value.id}}"}]) { +type Post + @http( + path: "/posts" + query: [{key: "id", value: "{{.value.id}}"}] + ) { id: Int! userId: Int! title: String! @@ -53,7 +57,10 @@ Example of `@apollo/gateway` configuration: ```ts import {ApolloServer} from "@apollo/server" import {startStandaloneServer} from "@apollo/server/standalone" -import {ApolloGateway, IntrospectAndCompose} from "@apollo/gateway" +import { + ApolloGateway, + IntrospectAndCompose, +} from "@apollo/gateway" const gateway = new ApolloGateway({ supergraphSdl: new IntrospectAndCompose({ @@ -85,7 +92,13 @@ type User @http(path: "/users/{{.args.id}}") @shareable { name: String! } -type Post @expr(body: {id: "{{.value.id}}", title: "post-title-{{.value.id}}"}) { +type Post + @expr( + body: { + id: "{{.value.id}}" + title: "post-title-{{.value.id}}" + } + ) { id: Int! title: String! @override(from: "name") } diff --git a/sidebars.ts b/sidebars.ts index 7f56f70eac..1734597720 100644 --- a/sidebars.ts +++ b/sidebars.ts @@ -47,7 +47,11 @@ const sidebars: SidebarsConfig = { "config-generation", ], }, - {type: "category", label: "Integrations", items: ["apollo-studio", "apollo-federation-subgraph", "data-dog", "new-relic", "honey-comb", "llm"]}, + { + type: "category", + label: "Integrations", + items: ["apollo-studio", "apollo-federation-subgraph", "data-dog", "new-relic", "honey-comb", "llm"], + }, { type: "category", label: "Production", From 721766714e590ddc119b4d9a8e64f3184ec271fc Mon Sep 17 00:00:00 2001 From: meskill <8974488+meskill@users.noreply.github.com> Date: Thu, 26 Sep 2024 15:10:40 +0000 Subject: [PATCH 3/4] update doc with flag --- docs/apollo-federation-subgraph.md | 8 ++++++++ docs/directives.md | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/docs/apollo-federation-subgraph.md b/docs/apollo-federation-subgraph.md index 833931cc76..6eadc991a4 100644 --- a/docs/apollo-federation-subgraph.md +++ b/docs/apollo-federation-subgraph.md @@ -13,6 +13,10 @@ First, you need to create a basic Tailcall configuration. For reference, check o ## Define Entity Resolvers +:::note +Skip this step if you don't have entities for now or want to add them later. +::: + Now you need to add [entity resolvers](https://www.apollographql.com/docs/federation/entities/) to the Tailcall config to make it act as a subgraph. To do this, you need to define resolver on types by using one of the [directives](./configuration.mdx) that resolve the data. Use [`{{.value}}`](https://tailcall.run/docs/graphql-resolver-context-tailcall/#value) to access the fields that act as a federation `@key` and will be provided by the Federation Router when making the request to this subgraph. @@ -34,6 +38,10 @@ type Post Please, note that you don't need to specify the `@key` directive manually when defining entity resolver with Tailcall. It's because Tailcall can automatically infer the key definitions from the usage of the resolver itself. ::: +## Enable federation in the Tailcall config + +Federation is controlled by the flag [`enableFederation`](./directives.md#enablefederation). In case you've added the entity resolvers on the previous step then federation compatibility will be enabled even without the flag. + ## Register your subgraph Registration of the subgraph depends on what Federation Router you use. diff --git a/docs/directives.md b/docs/directives.md index 8cda223903..1dd6037b37 100644 --- a/docs/directives.md +++ b/docs/directives.md @@ -1713,6 +1713,14 @@ schema @server(routes: {graphQL: "/tailcall-gql", status: "/health"}) In this example, the GraphQL endpoint is changed to `/tailcall-gql` and the status endpoint to `/health`. +### enableFederation + +A boolean flag, if set to `true` the Tailcall server will additionally act as federation subgraph. If set to `false` federation compatibility will be forcefully disabled. If flag is not set the federation compatibility is enabled automatically if any entity resolver is defined and disabled otherwise. + +```graphql showLineNumbers +schema @server(enableFederation: true) +``` + ## @telemetry Directive The `@telemetry` directive facilitates seamless integration with [OpenTelemetry](https://open-telemetry.io), enhancing the observability of your GraphQL services powered by Tailcall. By leveraging this directive, developers gain access to valuable insights into the performance and behavior of their applications. From cf49a203287b2419d0658345f6f573747c9343a3 Mon Sep 17 00:00:00 2001 From: meskill <8974488+meskill@users.noreply.github.com> Date: Fri, 27 Sep 2024 09:12:01 +0000 Subject: [PATCH 4/4] update sidebars.rs --- sidebars.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sidebars.ts b/sidebars.ts index 1734597720..010080d490 100644 --- a/sidebars.ts +++ b/sidebars.ts @@ -45,12 +45,13 @@ const sidebars: SidebarsConfig = { "environment-variables", "configuration", "config-generation", + "apollo-federation-subgraph", ], }, { type: "category", label: "Integrations", - items: ["apollo-studio", "apollo-federation-subgraph", "data-dog", "new-relic", "honey-comb", "llm"], + items: ["apollo-studio", "data-dog", "new-relic", "honey-comb", "llm"], }, { type: "category",