diff --git a/website/src/docs/fusion/v16/index.md b/website/src/docs/fusion/v16/index.md index 21e8b478ef1..63fe2147871 100644 --- a/website/src/docs/fusion/v16/index.md +++ b/website/src/docs/fusion/v16/index.md @@ -2,57 +2,39 @@ title: "Overview" --- -Fusion lets you split a GraphQL API across multiple independent services (subgraphs) while exposing a single, unified schema to clients. Clients query one endpoint; the gateway figures out which subgraphs to call and assembles the response. +Fusion lets you split one GraphQL API into multiple smaller services, without changing how clients consume it. Clients still send queries to one endpoint, and Fusion combines data from all services into one response. Teams can deploy independently, and contract conflicts are caught during build time. # What Is Fusion -Fusion is a distributed GraphQL architecture built on HotChocolate. You build each subgraph as a standard HotChocolate server, add a few annotations to describe how your types relate to the bigger graph, and let the Fusion gateway handle cross-service coordination. +Fusion is ChilliCream's API gateway for exposing one GraphQL API over multiple upstream services. Those upstream services can be GraphQL, OpenAPI-based REST, or gRPC. Each service owns its contract and implementation. Fusion composes those contracts at build time, and the gateway orchestrates execution at runtime. Fusion implements the [GraphQL Composite Schemas specification (draft)](https://graphql.github.io/composite-schemas-spec/draft/), an open standard being developed under the GraphQL Foundation. The architecture has three parts: -```text - ┌──────────┐ - │ Client │ - └────┬─────┘ - │ - ▼ - ┌────────────────┐ - │ Fusion Gateway │ - └──┬──────┬──┬───┘ - │ │ │ - ┌────────┘ │ └────────┐ - ▼ ▼ ▼ - ┌────────────┐ ┌────────────┐ ┌────────────┐ - │ Products │ │ Accounts │ │ Reviews │ - │ Subgraph │ │ Subgraph │ │ Subgraph │ - └──────┬─────┘ └──────┬─────┘ └──────┬─────┘ - │ │ │ - ▼ ▼ ▼ - ┌────────────┐ ┌────────────┐ ┌────────────┐ - │ Database A │ │ Database B │ │ Database C │ - └────────────┘ └────────────┘ └────────────┘ -``` +![Fusion Architecture Overview](../../shared/fusion/fusion-overview.png) + +**Subgraphs** are the upstream services behind the Fusion gateway: GraphQL services, OpenAPI-based REST services, and gRPC services. Each subgraph owns part of the API surface and implementation logic, and can be developed and deployed independently. + +A **source schema** is the contract document for a subgraph, such as a GraphQL schema, an OpenAPI document, or a gRPC/protobuf definition. -**Subgraphs** are HotChocolate servers with a few extra annotations. They own their data and their portion of the schema. They never call each other, never import each other's code, and can be deployed independently. +**Composition** processes all source schemas and produces a Fusion archive (`.far`) that contains the composite schema and gateway configuration. -**Composition** merges all subgraph schemas into a single composite schema and produces a gateway configuration file. This happens offline -- through the Nitro CLI or .NET Aspire -- not at runtime. If two subgraphs define conflicting types, composition fails with an error _before_ you deploy. +The **gateway** receives client requests, determines which subgraphs to call, executes those calls, and merges the results. -**The gateway** receives client queries, plans which subgraphs to call based on the composed configuration, executes those calls, and merges the results. You do not write routing logic or resolver code in the gateway. +The result: clients send one request to one endpoint and receive one unified response, while Fusion handles routing and aggregation across upstream services. -The result: a client sends a single query, the gateway fans it out to the relevant subgraphs, and the response comes back as if it were a monolithic API. +The following query touches three services, but the client doesn't know or care about this implementation detail. ```graphql -# This query touches three subgraphs, but the client doesn't know or care. query { products(first: 5) { nodes { - name # from Products subgraph - price # from Products subgraph - reviews { # from Reviews subgraph + name # from Products service + price # from Products service + reviews { # from Reviews service stars author { - username # from Accounts subgraph + username # from Accounts service } } } @@ -63,7 +45,17 @@ query { ## Three Things That Make Fusion Different -**Lookups are real Query fields.** When the gateway needs to resolve an entity from a subgraph, it calls a normal Query field annotated with `[Lookup]`. You can call the same field yourself in testing, debug it with standard tools, and see exactly what it returns. There is no hidden `_entities` field or magic resolution protocol. +A _lookup_ is a central concept in Fusion. It specifies how an entity can be resolved by a stable key. This concept also extends beyond federation and is useful in standard client-server communication. + +**Lookups use standard Query fields.** For GraphQL subgraphs, when the gateway needs to resolve an entity, it calls a normal Query field annotated with the `@lookup` directive. You can call the same field in tests, debug it with standard tools, and see exactly what it returns. There is no hidden internal protocol to implement, and the security model is the same as for any other GraphQL field. + +```graphql +type Query { + productById(id: ID!): Product @lookup +} +``` + +If you are using Hot Chocolate, support for the composite schema specification is built in. Add the `[Lookup]` attribute to your resolver and you are ready to go. ```csharp [QueryType] @@ -71,75 +63,75 @@ public static partial class ProductQueries { [Lookup] public static async Task GetProductById( - int id, + [ID] int id, IProductByIdDataLoader productById, CancellationToken cancellationToken) => await productById.LoadAsync(id, cancellationToken); } ``` -**Composition catches errors at build time.** When you run `nitro fusion compose`, the composition engine validates all subgraph schemas against each other. Type conflicts, missing fields, incompatible enums -- these are caught now, in your CI pipeline, not at 3 AM when a user hits a broken query path. +**Composition catches errors at build time.** When you run `nitro fusion compose`, the composition engine validates source schemas against each other. Type conflicts, missing fields, and incompatible enums are caught in CI before deployment. -**No federation runtime in your subgraphs.** Your subgraphs are standard HotChocolate servers. There is no subgraph library to install, no federation middleware to configure, no vendor-specific protocol. Your schemas follow the open [GraphQL Composite Schemas specification](https://graphql.github.io/composite-schemas-spec/draft/) being developed under the GraphQL Foundation. +**No special runtime for GraphQL subgraphs.** The [GraphQL Composite Schemas specification](https://graphql.github.io/composite-schemas-spec/draft/) is designed so a standard GraphQL server can already act as a compatible subgraph. In a common Hot Chocolate setup, subgraphs remain normal Hot Chocolate servers with regular resolvers, without a separate distributed-runtime package or vendor-specific protocol layer. # Key Terminology -| Term | Definition | -| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| **Subgraph** | A HotChocolate server that owns a portion of the overall schema. Each subgraph manages its own data and resolvers. | -| **Source schema** | The GraphQL schema exported by a single subgraph. This is what gets fed into composition. | -| **Composite schema** | The unified, client-facing schema produced by merging all source schemas. Clients query this schema as if it were a single API. | -| **Gateway** | The entry point for client requests. It receives queries against the composite schema, plans execution across subgraphs, and assembles responses. | -| **Entity** | A type that appears in more than one subgraph. For example, both the Products and Reviews subgraphs may define a `Product` type, each contributing different fields. | -| **Lookup** | A Query field annotated with `[Lookup]` that the gateway uses to resolve an entity from a subgraph. It is a standard, callable query field -- not a hidden internal mechanism. | -| **Composition** | The offline process of validating and merging source schemas into a composite schema and gateway configuration. Runs via the Nitro CLI or Aspire, not at runtime. | +| Term | Definition | +| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Subgraph** | An upstream service behind the Fusion gateway. A subgraph can be a GraphQL service, an OpenAPI-based REST service, or a gRPC service. | +| **Source schema** | The contract document published by one subgraph (for example a GraphQL schema, OpenAPI document, or gRPC/protobuf definition). | +| **Composite schema** | The unified, client-facing GraphQL schema produced during composition. Clients query this schema as if it were a single API. | +| **Gateway** | The public entry point for client requests. It receives queries against the composite schema, routes requests across subgraphs, and assembles responses. | +| **Entity** | A type with a stable key that can be referenced across GraphQL subgraphs. A subgraph can define an entity without resolving it locally. | +| **Lookup** | A Query field annotated with a `@lookup` directive that resolves an entity by key in that subgraph. | +| **Composition** | The offline step that validates source schemas and produces the composite schema and gateway configuration. Runs via the Nitro CLI or Aspire. | # When to Use Fusion -Fusion adds operational complexity -- a gateway process, a composition step in your build pipeline, distributed debugging. That complexity pays off in specific situations: +Fusion adds operational complexity, including a gateway process, a composition step in your build pipeline, and distributed debugging. That complexity pays off in specific situations: - **Multiple teams need to ship independently.** If different teams own different parts of your API (e.g., a product catalog team and a reviews team), Fusion lets each team deploy on their own schedule without coordinating schema changes through a shared codebase. -- **You need to scale services differently.** Your product search might need 10 instances while your user profile service needs 2. With separate subgraphs, you scale each service based on its actual load. +- **You need to scale services differently.** Your product search might need 10 instances while your user profile service needs 2. With separate services, you scale each one based on its actual load. -- **Your domain has clear boundaries.** If your data naturally splits into distinct areas (accounts, products, orders, reviews), subgraphs map well to those boundaries. Each subgraph owns its data store and its portion of the schema. +- **Your domain has clear boundaries.** If your data naturally splits into distinct areas (accounts, products, orders, reviews), separate services map well to those boundaries. Each service owns its data store and its API contract. -- **You want build-time validation of your distributed schema.** Composition catches conflicts between subgraphs before deployment. Your CI pipeline can validate that a schema change in one subgraph does not break the composed graph. +- **You want build-time validation of distributed contracts.** Composition catches conflicts between source schemas before deployment. Your CI pipeline can validate that a change in one service does not break the composed API. # When NOT to Use Fusion -Fusion is not the right choice for every project. Be honest about whether you need it: +Fusion is not the right choice for every project. Evaluate whether the additional complexity is justified: -- **One team, one service.** If a single team owns the entire API and deploys it as one unit, a standard HotChocolate server is simpler and has less operational overhead. You do not need a gateway, a composition pipeline, or distributed tracing for a single service. +- **One team, one service.** If one team owns the entire API and deploys it as a single unit, a standard Hot Chocolate server is simpler and has lower operational overhead. You likely do not need a gateway, a composition pipeline, or distributed tracing. -- **A small or early-stage API.** If your API has a handful of types and a few hundred queries per second, the added complexity of federation is not justified. Start with a monolith. You can split it later. +- **A small or early-stage API.** If your API has a handful of types and modest traffic, a distributed gateway setup often adds more complexity than value. Start with a monolith and split later when needed. Hot Chocolate supports an incremental path from monolith to modular monolith to distributed architecture. -- **No clear domain boundaries.** If your types are deeply intertwined and nearly every query touches every part of the schema, splitting into subgraphs will create more cross-service calls than it eliminates. Federation works best when subgraphs are relatively self-contained. +- **No clear domain boundaries.** If your types are deeply intertwined and most queries touch most of the schema, splitting into many services can create more cross-service calls than it removes. Fusion works best when services are relatively self-contained and have clear data contracts. -- **Your team is just getting started with GraphQL.** Learn HotChocolate first. Get comfortable with types, resolvers, DataLoaders, and the execution pipeline. Fusion adds concepts on top of that foundation -- it is easier to adopt once the basics are solid. +- **Your team is just getting started with GraphQL.** Learn GraphQL and Hot Chocolate first. Get comfortable with types, resolvers, DataLoaders, and the execution pipeline. Fusion adds concepts on top of that foundation and is easier to adopt once the basics are understood. -The cost of premature federation is real: more services to deploy, more infrastructure to monitor, harder debugging when something goes wrong. Start simple, and add Fusion when the pain of a monolith outweighs the cost of distribution. +The cost of premature distribution is real: more services to deploy, more infrastructure to monitor, and harder debugging when something goes wrong. Start simple, and add Fusion when the pain of a monolith outweighs the cost of distribution. # Migrating from a Monolith -If you already have a HotChocolate server, you are closer to Fusion than you think. Your existing server is already a valid subgraph -- it just happens to be the only one. +If you already have a Hot Chocolate server, you can adopt Fusion incrementally. -**Start with a "graph of one."** Point the Fusion gateway at your existing HotChocolate server as a single subgraph. Composition works with one source schema. Your clients connect to the gateway instead of directly to your server, but the behavior is identical. Nothing breaks. +**Start with one upstream service.** Point the Fusion gateway at your existing Hot Chocolate server as the only subgraph. Composition works with one source schema. Your clients connect to the gateway instead of directly to your server, but behavior stays the same. -**Add subgraphs incrementally.** When a new team or a new domain needs its own service, create a second subgraph. The new subgraph can extend types from the original server using entity stubs. Composition merges both schemas. The gateway handles cross-subgraph queries automatically. Your original server does not change. +**Add services incrementally.** When a new team or domain needs its own service, add another subgraph. The new service can extend types from the original service with entity stubs where needed. Composition merges both source schemas, and the gateway handles cross-service execution automatically. Your original service does not need a rewrite. -**Clients see no difference.** Whether you have one subgraph or ten, the composite schema looks the same to clients. You can split your monolith over weeks or months without ever breaking the client contract. +**Clients see no difference.** Whether you have one subgraph or ten, clients still call one endpoint and keep the same query surface. You can split your monolith over weeks or months without breaking the client contract. -The key insight: federation is not a rewrite. It is a gradual process. You move types and fields to new subgraphs one at a time, and the gateway smooths over the transition. +The key insight: this is not a rewrite. It is a gradual process. You move types and fields to new services over time, and the gateway smooths over the transition. # Next Steps Where you go from here depends on what you need: -- **"I want to build something."** Start with the [Getting Started](/docs/fusion/v16/getting-started) tutorial. You will create two subgraphs and a gateway from scratch. +- **"I want to build something."** Start with the [Getting Started](/docs/fusion/v16/getting-started) tutorial. You will create two services and a gateway from scratch. -- **"I want to add a subgraph to an existing project."** Go to [Adding a Subgraph](/docs/fusion/v16/adding-a-subgraph). It covers creating a new subgraph that extends existing entity types. +- **"I want to add another service to an existing project."** Go to [Adding a Subgraph](/docs/fusion/v16/adding-a-subgraph). It covers creating a new service (subgraph) that extends existing entity types. -- **"I'm migrating from another federation framework."** Read [Coming from Apollo Federation](/docs/fusion/v16/coming-from-apollo-federation) or [Migrating from Schema Stitching](/docs/fusion/v16/migrating-from-schema-stitching). These guides map familiar concepts to Fusion equivalents and walk through a migration. +- **"I'm migrating from another distributed GraphQL framework."** Read [Coming from Apollo Federation](/docs/fusion/v16/coming-from-apollo-federation) or [Migrating from Schema Stitching](/docs/fusion/v16/migrating-from-schema-stitching). These guides map familiar concepts to Fusion equivalents and walk through a migration. - **"I need to deploy this."** See [Deployment & CI/CD](/docs/fusion/v16/deployment-and-ci-cd) for pipeline setup, schema management, and gateway configuration. diff --git a/website/src/docs/shared/fusion/fusion-overview.png b/website/src/docs/shared/fusion/fusion-overview.png new file mode 100644 index 00000000000..c98c4fd8edc Binary files /dev/null and b/website/src/docs/shared/fusion/fusion-overview.png differ