Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update migration guide with findings #7625

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,22 @@ builder.Services
.AddGlobalObjectIdentification();
```

## IIdSerializer replaced by INodeIdSerializer

Previously, you could grab the `IIdSerializer` from your dependency injection container to manually parse and serialize globally unique identifiers (GID).
As part of the changes to the GID format mentioned above, the `IIdSerializer` interface has been renamed to `INodeIdSerializer`.

The methods used for parsing and serialization have also been renamed:

| Before | After |
| ---------------------------------- | ---------------------------------------------------------------------------------------- |
| `.Deserialize("<gid-value>")` | `.Parse("<gid-value>", typeof(string))` where `string` is the underlying type of the GID |
| `.Serialize("MyType", "<raw-id>")` | `.Format("MyType", "<raw-id>")` |
tobias-tengler marked this conversation as resolved.
Show resolved Hide resolved

The `Parse()` (previously `Deserialize()`) method has also changed its return type from `IdValue` to `NodeId`. The parsed Id value can now be accessed through the `NodeId.InternalId` instead of the `IdValue.Value` property.

The ability to encode the schema name in the GID via `.Serialize("SchemaName", "MyType", "<raw-id>")` has been dropped and is no longer supported.

## Node Resolver validation

We now enforce that each object type implementing the `Node` interface also defines a resolver, so that the object can be refetched through the `node(id: ID!)` field.
Expand All @@ -136,6 +152,11 @@ builder.Services
.ModifyOptions(o => o.EnsureAllNodesCanBeResolved = false)
```

## DataLoader.LoadAsync always returns nullable type

Previously, the `LoadAsync` method on a DataLoader was typed as non-nullable, even though `null` could be returned.
This release changes the return type of `LoadAsync` to always be nullable.

## Builder APIs

We have aligned all builder APIs to be more consistent and easier to use. Builders can now be created by using the static method `Builder.New()` and the `Build()` method to create the final object.
Expand All @@ -144,9 +165,14 @@ We have aligned all builder APIs to be more consistent and easier to use. Builde

The interface `IQueryRequestBuilder` and its implementations were replaced with `OperationRequestBuilder` which now supports building standard GraphQL operation requests as well as variable batch requests.

The `Build()` method returns now a `IOperationRequest` which is implemented by `OperationRequest` and `VariableBatchRequest`.
The `Build()` method now returns a `IOperationRequest` which is implemented by `OperationRequest` and `VariableBatchRequest`.

We've also renamed and consolidated some methods on the `OperationRequestBuilder`:

We have also simplified what the builder does and removed a lot of the convenience methods that allowed to add single variables to it. This has todo with the support of variable batching. Now, you have to provide the variable map directly.
| Before | After |
| ----------------------------------- | --------------------------------------------------------------------------- |
| `SetQuery("{ __typename }")` | `SetDocument("{ __typename }")` |
| `AddVariableValue("name", "value")` | `AddVariableValues(new Dictionary<string, object?> { ["name"] = "value" })` |

### IQueryResultBuilder replaced by OperationResultBuilder

Expand All @@ -156,6 +182,11 @@ The interface `IQueryResultBuilder` and its implementations were replaced with `

The interface `IQueryResult` was replaced with `IOperationResult`.

### IExecutionResult.ExpectQueryResult replaced by .ExpectOperationResult

In your unit tests you might have been using `result.ExpectQueryResult()` to assert that a result is not a streamed response and rather a completed result.
This assertion method has been renamed to `ExpectOperationResult()`.

## Operation complexity analyzer replaced

The Operation Complexity Analyzer in v13 has been replaced by Cost Analysis in v14, based on the draft [IBM Cost Analysis specification](https://ibm.github.io/graphql-specs/cost-spec.html).
Expand Down Expand Up @@ -252,6 +283,38 @@ ModifyRequestOptions(o => o.OnlyAllowPersistedOperations = true);
ModifyRequestOptions(o => o.PersistedOperations.OnlyAllowPersistedDocuments = true);
```

## Connection getTotalCount constructor argument replaced with totalCount

Previously, you could supply an async method to the `getTotalCount` constructor argument when instantiating a `Connection<T>`. This method would only be evaluated to calculate the total count, if the `totalCount` field was selected on that Connection in a query.

```csharp
return new Connection<MyType>(
edges: [/* ... */],
info: new ConnectionPageInfo(/* ... */),
getTotalCount: async cancellationToken => 123)
```

In this release the constructor argument was renamed to `totalCount` and now only accepts an `int` for the total count, no longer a method to compute the total count.
If you want to re-create the old behavior, you can use the new `[IsSelected]` attribute to conditionally compute the total count.

```csharp
public Connection<MyType> GetMyTypes(
[IsSelected("totalCount")] bool hasSelectedTotalCount,
CancellationToken cancellationToken)
{
var totalCount = 0;
if (hasSelectedTotalCount)
{
totalCount = /* ... */;
}

return new Connection<MyType>(
edges: [/* ... */],
info: new ConnectionPageInfo(/* ... */),
totalCount: totalCount)
}
```

# Deprecations

Things that will continue to function this release, but we encourage you to move away from.
Expand Down
Loading