Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ accessibilities
agrc
Alderaan
Andi
appsettings
ASPDEPR004
ASPDEPR008
aspnet
aspnetcore
Astromech
automagically
Expand Down Expand Up @@ -37,6 +39,7 @@ combinators
contentfiles
Contoso
CQRS
creds
dataloaders
debuggable
decompile
Expand Down Expand Up @@ -157,6 +160,7 @@ runbooks
Satisfiability
Senn
shoooe
SHORTSHA
Silmarillion
skybridge
Skywalker
Expand Down Expand Up @@ -184,6 +188,7 @@ Tatooine
Tengler
Testcontainers
Toub
Touchpoint
TOWGS
Trimmable
Tzdb
Expand Down
44 changes: 22 additions & 22 deletions website/src/docs/fusion/v16/attribute-and-directive-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,28 @@ Quick reference for all Fusion-related attributes and their GraphQL directive eq

# Attribute and Directive Reference Table

| Attribute | Directive | Description | Guide Page |
|---|---|---|---|
| `[ObjectType<T>]` | — | Maps static class as extension to entity type T | [Entities and Lookups](/docs/fusion/v16/entities-and-lookups) |
| `[QueryType]` | — | Marks class as contributing Query root fields | [Getting Started](/docs/fusion/v16/getting-started) |
| `[MutationType]` | — | Marks class as contributing Mutation root fields | [Getting Started](/docs/fusion/v16/getting-started) |
| `[SubscriptionType]` | — | Marks class as contributing Subscription root fields | [Getting Started](/docs/fusion/v16/getting-started) |
| `[Lookup]` | `@lookup` | Declares field as entity lookup resolver | [Entities and Lookups](/docs/fusion/v16/entities-and-lookups) |
| `[NodeResolver]` | — | Marks as Relay node resolver | [Entities and Lookups](/docs/fusion/v16/entities-and-lookups) |
| `[Internal]` | `@internal` | Hides lookup from composed schema | [Entities and Lookups](/docs/fusion/v16/entities-and-lookups) |
| `[Shareable]` | `@shareable` | Allows multiple subgraphs to resolve field | [Entities and Lookups](/docs/fusion/v16/entities-and-lookups) |
| `[Parent(requires: "...")]` | — | Declares field requirements from parent | [Entities and Lookups](/docs/fusion/v16/entities-and-lookups) |
| `[Require("...")]` | `@require` | Declares complex field requirements | [Getting Started](/docs/fusion/v16/getting-started), [Adding a Subgraph](/docs/fusion/v16/adding-a-subgraph) |
| `[EntityKey("...")]` | `@key` | Declares entity key for resolution | [Entities and Lookups](/docs/fusion/v16/entities-and-lookups) |
| `[BindMember(nameof(...))]` | — | Replaces raw FK with resolved entity | [Adding a Subgraph](/docs/fusion/v16/adding-a-subgraph) |
| `[Tag("...")]` | `@tag` | Applies tag for composition filtering | [Composition](/docs/fusion/v16/composition) |
| `[DataLoader]` | — | Source-generates DataLoader interface | [Getting Started](/docs/fusion/v16/getting-started), [Entities and Lookups](/docs/fusion/v16/entities-and-lookups) |
| `[UsePaging]` | — | Enables cursor-based pagination | [Getting Started](/docs/fusion/v16/getting-started) |
| `[ID<T>]` | — | Declares field as Relay-style ID | [Entities and Lookups](/docs/fusion/v16/entities-and-lookups) |
| `[Inaccessible]` | `@inaccessible` | Hides from composite schema | [Composition](/docs/fusion/v16/composition) |
| `[Override(from: "...")]` | `@override` | Migrates field ownership | [Deployment and CI/CD](/docs/fusion/v16/deployment-and-ci-cd) |
| `[Provides("...")]` | `@provides` | Declares locally-resolvable subfields | [Entities and Lookups](/docs/fusion/v16/entities-and-lookups) |
| `[External]` | `@external` | Field defined by another subgraph | [Entities and Lookups](/docs/fusion/v16/entities-and-lookups) |
| Attribute | Directive | Description | Guide Page |
| --------------------------- | --------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `[ObjectType<T>]` | — | Maps static class as extension to entity type T | [Entities and Lookups](/docs/fusion/v16/entities-and-lookups) |
| `[QueryType]` | — | Marks class as contributing Query root fields | [Getting Started](/docs/fusion/v16/getting-started) |
| `[MutationType]` | — | Marks class as contributing Mutation root fields | [Getting Started](/docs/fusion/v16/getting-started) |
| `[SubscriptionType]` | — | Marks class as contributing Subscription root fields | [Getting Started](/docs/fusion/v16/getting-started) |
| `[Lookup]` | `@lookup` | Declares field as entity lookup resolver | [Entities and Lookups](/docs/fusion/v16/entities-and-lookups) |
| `[NodeResolver]` | — | Marks as Relay node resolver | [Entities and Lookups](/docs/fusion/v16/entities-and-lookups) |
| `[Internal]` | `@internal` | Hides lookup from composed schema | [Entities and Lookups](/docs/fusion/v16/entities-and-lookups) |
| `[Shareable]` | `@shareable` | Allows multiple subgraphs to resolve field | [Entities and Lookups](/docs/fusion/v16/entities-and-lookups) |
| `[Parent(requires: "...")]` | — | Declares field requirements from parent | [Entities and Lookups](/docs/fusion/v16/entities-and-lookups) |
| `[Require("...")]` | `@require` | Declares complex field requirements | [Getting Started](/docs/fusion/v16/getting-started), [Adding a Subgraph](/docs/fusion/v16/adding-a-subgraph) |
| `[EntityKey("...")]` | `@key` | Declares entity key for resolution | [Entities and Lookups](/docs/fusion/v16/entities-and-lookups) |
| `[BindMember(nameof(...))]` | — | Replaces raw FK with resolved entity | [Adding a Subgraph](/docs/fusion/v16/adding-a-subgraph) |
| `[Tag("...")]` | `@tag` | Applies tag for composition filtering | [Composition](/docs/fusion/v16/composition) |
| `[DataLoader]` | — | Source-generates DataLoader interface | [Getting Started](/docs/fusion/v16/getting-started), [Entities and Lookups](/docs/fusion/v16/entities-and-lookups) |
| `[UsePaging]` | — | Enables cursor-based pagination | [Getting Started](/docs/fusion/v16/getting-started) |
| `[ID<T>]` | — | Declares field as Relay-style ID | [Entities and Lookups](/docs/fusion/v16/entities-and-lookups) |
| `[Inaccessible]` | `@inaccessible` | Hides from composite schema | [Composition](/docs/fusion/v16/composition) |
| `[Override(from: "...")]` | `@override` | Migrates field ownership | [Deployment and CI/CD](/docs/fusion/v16/deployment-and-ci-cd) |
| `[Provides("...")]` | `@provides` | Declares locally-resolvable subfields | [Entities and Lookups](/docs/fusion/v16/entities-and-lookups) |
| `[External]` | `@external` | Field defined by another subgraph | [Entities and Lookups](/docs/fusion/v16/entities-and-lookups) |

# See Also

Expand Down
44 changes: 22 additions & 22 deletions website/src/docs/fusion/v16/coming-from-apollo-federation.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,23 @@ This guide maps Apollo Federation concepts to their Fusion equivalents, explains

The table below maps Apollo Federation concepts to their Fusion equivalents. Some are straightforward renames; others involve meaningful behavioral changes. The "Key Difference" column flags which is which.

| Apollo Federation | HotChocolate Fusion | Key Difference |
|---|---|---|
| `@key(fields: "id")` | `[Lookup]` on a Query field | Fusion uses explicit, typed lookup fields instead of implicit `_entities`. No `@key` directive needed. |
| `__resolveReference` / `_entities` query | Regular Query fields with `[Lookup]` | Lookups are real fields you can call and test directly. |
| `@external` | `[External]` (rarely needed) | Same concept, but less frequently needed in Fusion. |
| `@requires(fields: "...")` on a field | `[Require("...")]` on an argument | Argument-level, not field-level. Required arguments are hidden from the composite schema. |
| `@provides(fields: "...")` | `[Provides("...")]` / `[Parent(requires: "...")]` | Same optimization concept. |
| `@shareable` | `[Shareable]` | Same concept and semantics. Key fields are automatically shareable. |
| `@override(from: "...")` | `[Override(from: "...")]` | Same concept. |
| `@inaccessible` | `[Inaccessible]` | Same concept. |
| `@tag` | `[Tag]` | Same concept. |
| Apollo Router / Gateway | Fusion Gateway (`AddGraphQLGateway()`) | A .NET ASP.NET Core app, not a separate binary. |
| `rover` CLI | Nitro CLI (`nitro fusion ...`) | Schema composition, validation, and delivery. |
| GraphOS managed federation | Nitro cloud or local CI/CD composition | Build-time composition. Works fully offline. |
| Supergraph schema (SDL) | Composite schema + `.far` archive | Binary archive containing the composed schema and subgraph metadata. |
| Federation subgraph library (`@apollo/subgraph`) | No equivalent needed | Subgraphs are standard HotChocolate servers. No federation library. |
| `_service { sdl }` introspection | `dotnet run -- schema export` | Schema export is a CLI command, not a runtime introspection field. |
| Apollo Federation | HotChocolate Fusion | Key Difference |
| ------------------------------------------------ | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| `@key(fields: "id")` | `[Lookup]` on a Query field | Fusion uses explicit, typed lookup fields instead of implicit `_entities`. No `@key` directive needed. |
| `__resolveReference` / `_entities` query | Regular Query fields with `[Lookup]` | Lookups are real fields you can call and test directly. |
| `@external` | `[External]` (rarely needed) | Same concept, but less frequently needed in Fusion. |
| `@requires(fields: "...")` on a field | `[Require("...")]` on an argument | Argument-level, not field-level. Required arguments are hidden from the composite schema. |
| `@provides(fields: "...")` | `[Provides("...")]` / `[Parent(requires: "...")]` | Same optimization concept. |
| `@shareable` | `[Shareable]` | Same concept and semantics. Key fields are automatically shareable. |
| `@override(from: "...")` | `[Override(from: "...")]` | Same concept. |
| `@inaccessible` | `[Inaccessible]` | Same concept. |
| `@tag` | `[Tag]` | Same concept. |
| Apollo Router / Gateway | Fusion Gateway (`AddGraphQLGateway()`) | A .NET ASP.NET Core app, not a separate binary. |
| `rover` CLI | Nitro CLI (`nitro fusion ...`) | Schema composition, validation, and delivery. |
| GraphOS managed federation | Nitro cloud or local CI/CD composition | Build-time composition. Works fully offline. |
| Supergraph schema (SDL) | Composite schema + `.far` archive | Binary archive containing the composed schema and subgraph metadata. |
| Federation subgraph library (`@apollo/subgraph`) | No equivalent needed | Subgraphs are standard HotChocolate servers. No federation library. |
| `_service { sdl }` introspection | `dotnet run -- schema export` | Schema export is a CLI command, not a runtime introspection field. |

## What Fusion Does Not Need

Expand Down Expand Up @@ -618,11 +618,11 @@ Navigate to `http://localhost:5000/graphql` to open the Nitro IDE and run cross-

Replace Apollo's `rover` commands with Nitro CLI equivalents.

| Apollo (`rover`) | Fusion (`nitro`) |
|---|---|
| `rover subgraph check` | `nitro fusion validate` |
| `rover subgraph publish` | `nitro fusion upload` + `nitro fusion publish` |
| `rover supergraph compose` | `nitro fusion compose` |
| Apollo (`rover`) | Fusion (`nitro`) |
| -------------------------- | ---------------------------------------------- |
| `rover subgraph check` | `nitro fusion validate` |
| `rover subgraph publish` | `nitro fusion upload` + `nitro fusion publish` |
| `rover supergraph compose` | `nitro fusion compose` |

#### Schema Upload (Replaces `rover subgraph publish`)

Expand Down
35 changes: 22 additions & 13 deletions website/src/docs/fusion/v16/composition.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,23 +149,23 @@ When the same field appears in multiple subgraphs with different nullability, th

For output fields -- fields returned by resolvers -- the merged type uses the **least restrictive** nullability. Nullable wins:

| Subgraph A | Subgraph B | Composed Result |
|------------|------------|-----------------|
| Subgraph A | Subgraph B | Composed Result |
| --------------- | --------------- | --------------- |
| `name: String!` | `name: String!` | `name: String!` |
| `name: String!` | `name: String` | `name: String` |
| `name: String` | `name: String` | `name: String` |
| `name: String!` | `name: String` | `name: String` |
| `name: String` | `name: String` | `name: String` |

Why? If one subgraph says a field can be null, the gateway must account for that possibility. The composed schema reflects the reality that the field might be null from at least one source.

### Arguments and Input Fields (Most Restrictive)

For arguments and input object fields -- values provided by clients -- the merged type uses the **most restrictive** nullability. Non-nullable wins:

| Subgraph A | Subgraph B | Composed Result |
|------------|------------|-----------------|
| `limit: Int!` | `limit: Int!` | `limit: Int!` |
| `limit: Int!` | `limit: Int` | `limit: Int!` |
| `limit: Int` | `limit: Int` | `limit: Int` |
| Subgraph A | Subgraph B | Composed Result |
| ------------- | ------------- | --------------- |
| `limit: Int!` | `limit: Int!` | `limit: Int!` |
| `limit: Int!` | `limit: Int` | `limit: Int!` |
| `limit: Int` | `limit: Int` | `limit: Int` |

Why? If one subgraph requires a non-nullable argument, the gateway must always provide it. Clients must supply a value that satisfies the strictest subgraph.

Expand Down Expand Up @@ -482,10 +482,19 @@ public static partial class ProductQueries

```graphql
# Orders subgraph
enum OrderStatus { PENDING, SHIPPED, DELIVERED, CANCELLED }
enum OrderStatus {
PENDING
SHIPPED
DELIVERED
CANCELLED
}

# Payments subgraph (used as input)
enum OrderStatus { PENDING, SHIPPED, DELIVERED }
enum OrderStatus {
PENDING
SHIPPED
DELIVERED
}
# Missing CANCELLED!
```

Expand Down Expand Up @@ -520,7 +529,7 @@ type DigitalProduct implements Purchasable {
# Payments subgraph
interface Purchasable {
price: Float!
refundPolicy: String! # New field added here
refundPolicy: String! # New field added here
}
```

Expand All @@ -544,7 +553,7 @@ After merging, the `Purchasable` interface has both `price` and `refundPolicy`.

**Fix:** Ensure both files exist and share the same prefix:

```
```text
Products/
├── schema.graphqls
└── schema-settings.json
Expand Down
14 changes: 11 additions & 3 deletions website/src/docs/fusion/v16/deployment-and-ci-cd.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ nitro fusion publish \
```

This command:

1. Downloads all source schemas for the specified stage
2. Composes them into a gateway configuration
3. Validates compatibility
Expand Down Expand Up @@ -171,6 +172,7 @@ nitro fusion validate \
```

Exit codes:

- `0`: Validation passed
- Non-zero: Validation failed (breaking change detected)

Expand Down Expand Up @@ -376,14 +378,17 @@ jobs:
## Workflow Explanation

### Version Job

Generates a timestamp-based tag and version string from the current git commit SHA.

### Build Job

1. **Restore and publish** — `dotnet publish` produces a container image and pushes to Azure Container Registry
2. **Export schema** — `dotnet run -- schema export` generates the `.graphqls` file
3. **Upload to Nitro** — `nitro fusion upload` versions the schema in Nitro cloud

### Deploy Job

1. **Create or update App Service** — Deploys the container image to Azure App Service
2. **Publish to Nitro** — `nitro fusion publish` triggers server-side composition and deploys the new configuration to the specified stage
3. **Gateway hot-reloads** — The gateway automatically downloads the new config from Nitro
Expand All @@ -397,10 +402,10 @@ For simpler pipelines, use the pre-built action:
uses: ChilliCream/nitro-fusion-publish-action@v1
with:
tag: ${{ github.ref_name }}
stage: 'production'
api-id: 'QXBpCmcwMTk5MGUzNDVlMWU3MjMyYjc2MjYxYzFiNjRkMGQzYg=='
stage: "production"
api-id: "QXBpCmcwMTk5MGUzNDVlMWU3MjMyYjc2MjYxYzFiNjRkMGQzYg=="
api-key: ${{ secrets.NITRO_API_KEY }}
source-schema-file: './src/Products/schema.graphqls'
source-schema-file: "./src/Products/schema.graphqls"
```

# Gateway Configuration
Expand Down Expand Up @@ -468,6 +473,7 @@ For bidirectional subscriptions, configure WebSocket transport. Subscriptions co
## Defaults

By default:

- All HTTP requests use the `"fusion"` named HTTP client
- Requests are not batched unless explicitly enabled
- Subscriptions use SSE if available, otherwise HTTP polling
Expand Down Expand Up @@ -554,12 +560,14 @@ This lets you develop and test new features without exposing them to clients unt
## Breaking vs. Non-Breaking Changes

### Non-Breaking Changes

- Adding a new type
- Adding a new field to an existing type (nullable or with a default)
- Adding a new optional argument to a field
- Marking a field as `[Shareable]` (allowing multiple subgraphs to resolve it)

### Breaking Changes

- Removing a type or field
- Changing a field's return type
- Changing a field's arguments
Expand Down
Loading
Loading