#12752 8b779b4 Thanks @jerelmiller! - Add deprecations and warnings to remaining APIs changed in Apollo Client 4.0.
#12751 567cad8 Thanks @jerelmiller! - Add @deprecated tags to all properties returned from any query API (e.g. client.query, observableQuery.refetch, etc.), client.mutate, and client.subscribe that are no longer available in Apollo Client 4.0.
#12751 567cad8 Thanks @jerelmiller! - Warn when using a standby fetch policy with client.query.
#12746 0bcd2f4 Thanks @jerelmiller! - Add warnings and deprecations for options and methods for all React APIs.
#12746 0bcd2f4 Thanks @jerelmiller! - Add preloadQuery.toPromise(queryRef) as a replacement for queryRef.toPromise(). queryRef.toPromise() has been removed in Apollo Client 4.0 in favor of preloadQuery.toPromise and is now considered deprecated.
#12736 ea89440 Thanks @jerelmiller! - Add deprecations and deprecation warnings for ApolloClient options and methods.
#12459 1c5a031 Thanks @jerelmiller! - Reset addTypenameTransform and fragments caches when calling cache.gc() only when resetResultCache is true.
#12743 92ad409 Thanks @jerelmiller! - Add deprecations and warnings for addTypename in InMemoryCache and MockedProvider.
#12743 92ad409 Thanks @jerelmiller! - Add deprecations and warnings for canonizeResults.
#12727 b845906 Thanks @jerelmiller! - Add a codemod that renames old import locations from 3.x entrypoint to their 4.x entrypoint.
Run the codemod using the following command:
npx @apollo/client-codemod-migrate-3-to-4 --parser tsx ./src/**/*.{ts,tsx}
The codemod supports .js, .jsx, .ts, and .tsx files.
#12742 575bf3e Thanks @jerelmiller! - The new SetContextLink flips the prevContext and operation arguments in the callback. The setContext function has remained unchanged.
- new SetContextLink((operation, prevContext) => {
+ new SetContextLink((prevContext, operation) => {
// ...
})
#12742 575bf3e Thanks @jerelmiller! - The operation argument to the callback passed to SetContextLink is now of type SetContextLink.SetContextOperation which is an Operation without the getContext or setContext functions. Previously the type of operation was GraphQLRequest which had access to a context property. The context property was always undefined and could result in bugs when using it instead of the prevContext argument.
This change means the operation argument now contains an accessible client property.
#12740 1c6e03c Thanks @phryneas! - Overridable types for dataState: "complete", dataState: "streaming" and
dataState: "partial" responses.
This adds the DataValue namespace exported from Apollo Client with the three
types DataValue.Complete, DataValue.Streaming and DataValue.Partial.
These types will be used to mark TData in the respective states.
Complete defaults to TDataStreaming defaults to TDataPartial defaults to DeepPartial<TData>All three can be overwritten, e.g. to be DeepReadonly using higher kinded types
by following this pattern:
import { HKT, DeepPartial } from "@apollo/client/utilities";
import { DeepReadonly } from "some-type-helper-library";
interface CompleteOverride extends HKT {
return: DeepReadonly<this["arg1"]>;
}
interface StreamingOverride extends HKT {
return: DeepReadonly<this["arg1"]>;
}
interface PartialOverride extends HKT {
return: DeepReadonly<DeepPartial<this["arg1"]>>;
}
declare module "@apollo/client" {
export interface TypeOverrides {
Complete: CompleteOverride;
Streaming: StreamingOverride;
Partial: PartialOverride;
}
}
#12735 5159880 Thanks @jerelmiller! - Remove deprecated resultCacheMaxSize option from InMemoryCache options.
#12735 5159880 Thanks @jerelmiller! - Remove deprecated connectToDevtools option from ApolloClientOptions. Use devtools.enabled instead.
#12725 89ac725 Thanks @jerelmiller! - Add operationType to operation in ApolloLink. This means that determining whether a query is a specific operation type can now be compared with this property instead of using getMainDefinition.
- import { getMainDefinition } from "@apollo/client/utilities";
+ import { OperationTypeNode } from "graphql";
ApolloLink.split(
- ({ query }) => {
- const definition = getMainDefinition(query);
- return (
- definition.kind === 'OperationDefinition' &&
- definition.operation === 'subscription'
- );
- return
- },
+ ({ operationType }) => {
+ return operationType === OperationTypeNode.SUBSCRIPTION;
+ },
conditionTrueLink,
conditionFalseLink,
);
#12728 07a0c8c Thanks @jerelmiller! - Export the IgnoreModifier type from @apollo/client/cache.
#12735 5159880 Thanks @jerelmiller! - Change the unsafePreviousData argument on UpdateQueryMapFn and SubscribeToMoreQueryFn to a DeepPartial since the result may contain partial data.
#12734 037979d Thanks @jerelmiller! - Don't warn about a missing resolver if a @client does not have a configured resolver. It is possible the cache contains a read function for the field and the warning added confusion.
Note that read functions without a defined resolver will receive the existing argument as null instead of undefined even when data hasn't been written to the cache. This is because LocalState sets a default value of null when a resolver is not defined to ensure that the field contains a value in case a read function is not defined rather than omitting the field entirely.
#12725 89ac725 Thanks @jerelmiller! - Export getMainDefinition from @apollo/client/utilities.
#12729 699c830 Thanks @jerelmiller! - Ensure useQuery rerenders when notifyOnNetworkStatusChange is false and a refetch that changes variables returns a result deeply equal to previous variables.
1f9ed72 Thanks @jerelmiller! - Version bump only for codegen to release as rc.ecfc02a Thanks @jerelmiller! - Version bump only to release latest as rc.#12712 bbb2b61 Thanks @jerelmiller! - An error is now thrown when trying to call fetchMore on a cache-only query.
#12712 bbb2b61 Thanks @jerelmiller! - cache-only queries are no longer refetched when calling client.reFetchObservableQueries when includeStandby is true.
#12705 a60f411 Thanks @jerelmiller! - cache-only queries will now initialize with loading: false and networkStatus: NetworkStatus.ready when there is no data in the cache.
This means useQuery will no longer render a short initial loading state before rendering loading: false and ObservableQuery.getCurrentResult() will now return loading: false immediately.
#12712 bbb2b61 Thanks @jerelmiller! - cache-only queries are now excluded from client.refetchQueries in all situations. cache-only queries affected by updateCache are also excluded from refetchQueries when onQueryUpdated is not provided.
#12681 b181f98 Thanks @jerelmiller! - Changing most options when rerendering useQuery will no longer trigger a reobserve which may cause network fetches. Instead, the changed options will be applied to the next cache update or fetch.
Options that now trigger a reobserve when changed between renders are:
queryvariablesskipfetchPolicy to or from standby#12714 0e39469 Thanks @phryneas! - Rework option handling for fetchMore.
query option was specified, no options would be inherited
from the underlying ObservableQuery.
Now, even if query is specified, all unspecified options except for variables will be inherited from the underlying ObservableQuery.query is not specified, variables will still be shallowly merged with the variables of the underlying ObservableQuery. If a query option is specified, the variables passed to fetchMore are used instead.errorPolicy of fetchMore will now always default to "none" instead of inherited from the ObservableQuery options. This can prevent accidental cache writes of partial data for a paginated query. To opt into receive partial data that may be written to the cache, pass an errorPolicy to fetchMore to override the default.#12700 8e96e08 Thanks @phryneas! - Added a new Streaming type that will mark data in results while dataStatus
is "streaming".
Streaming<TData> defaults to TData, but can be overwritten in userland to
integrate with different codegen dialects.
You can override this type globally - this example shows how to override it
with DeepPartial<TData>:
import { HKT, DeepPartial } from "@apollo/client/utilities";
type StreamingOverride<TData> = DeepPartial<TData>;
interface StreamingOverrideHKT extends HKT {
return: StreamingOverride<this["arg1"]>;
}
declare module "@apollo/client" {
export interface TypeOverrides {
Streaming: StreamingOverrideHKT;
}
}
#12499 ce35ea2 Thanks @phryneas! - Enable React compiler for hooks in ESM builds.
#12704 45dba43 Thanks @jerelmiller! - The ErrorResponse object passed to the disable and retry callback options provided to createPersistedQueryLink no longer provides separate graphQLErrors and networkError properties and instead have been combined to a single error property of type ErrorLike.
// The following also applies to the `retry` function since it has the same signature
createPersistedQueryLink({
- disable: ({ graphQLErrors, networkError }) => {
+ disable: ({ error }) => {
- if (graphQLErrors) {
+ if (CombinedGraphQLErrors.is(error)) {
// ... handle GraphQL errors
}
- if (networkError) {
+ if (error) {
// ... handle link errors
}
// optionally check for a specific kind of error
- if (networkError) {
+ if (ServerError.is(error)) {
// ... handle a server error
}
});
The response property has also been renamed to result.
createPersistedQueryLink({
- disable: ({ response }) => {
+ disable: ({ result }) => {
// ... handle GraphQL errors
}
}
});
#12712 bbb2b61 Thanks @jerelmiller! - cache-only queries no longer poll when a pollInterval is set. Instead a warning is now emitted that polling has no effect. If the fetchPolicy is changed to cache-only after polling is already active, polling is stopped.
#12704 45dba43 Thanks @jerelmiller! - The response property in onError link has been renamed to result.
- onError(({ response }) => {
+ onError(({ result }) => {
// ...
});
#12715 0be0b3f Thanks @phryneas! - All links are now available as classes. The old creator functions have been deprecated.
Please migrate these function calls to class creations:
import {
- setContext
+ SetContextLink
} from "@apollo/client/link/context"
-const link = setContext(...)
+const link = new SetContextLink(...)
import {
- createHttpLink
+ HttpLink
} from "@apollo/client/link/http"
-const link = createHttpLink(...)
+const link = new HttpLink(...)
import {
- createPersistedQueryLink
+ PersistedQueryLink
} from "@apollo/client/link/persisted-queries"
-const link = createPersistedQueryLink(...)
+const link = new PersistedQueryLink(...)
import {
- removeTypenameFromVariables
+ RemoveTypenameFromVariablesLink
} from "@apollo/client/link/remove-typename"
-const link = removeTypenameFromVariables(...)
+const link = new RemoveTypenameFromVariablesLink(...)
#12711 f730f83 Thanks @jerelmiller! - Add an extensions property to CombinedGraphQLErrors to capture any extensions from the original response.
#12700 8e96e08 Thanks @phryneas! - The callback function that can be passed to the ApolloClient.mutate
refetchQueries option will now receive a FormattedExecutionResult with an
additional dataState option that describes if the result is "streaming"
or "complete".
This indicates whether the data value is of type
Unmasked<TData> (if "complete")Streaming<Unmasked<TData>> (if "streaming")#12714 0e39469 Thanks @phryneas! - Allow passing errorPolicy option to fetchMore and change default value to "none".
#12714 0e39469 Thanks @phryneas! - The FetchMoreQueryOptions type has been inlined into FetchMoreOptions, and
FetchMoreQueryOptions has been removed.
#12700 8e96e08 Thanks @phryneas! - Prioritize usage of FormattedExecutionResult over FetchResult where applicable.
Many APIs used FetchResult in place of FormattedExecutionResult, which could
cause inconsistencies.
FetchResult is now used to refer to an unhandled "raw" result as returned from
a link.
This can also include incremental results that use a different format.FormattedExecutionResult from the graphql package is now used to represent
the execution of a standard GraphQL request without incremental results.If your custom links access the data property, you might need to first check if
the result is a standard GraphQL result by using the isFormattedExecutionResult
helper from @apollo/client/utilities.
#12700 8e96e08 Thanks @phryneas! - The mutationResult option passed to the updateQueries callback now has an
additional property, dataState with possible values of "complete" and "streaming".
This indicates whether the data value is of type
Unmasked<TData> (if "complete")Streaming<Unmasked<TData>> (if "streaming")#12709 9d42e2a Thanks @phryneas! - Remove these incremental-format-specific types:
ExecutionPatchIncrementalResultExecutionPatchInitialResultExecutionPatchResultIncrementalPayloadPath#12677 94e58ed Thanks @jerelmiller! - Downgrade minimum supported rxjs peer dependency version to 7.3.0.
#12709 9d42e2a Thanks @phryneas! - Slightly rework multipart response parsing.
This removes last incremental-protocol-specific details from HttpLink and BatchHttpLink.
#12700 8e96e08 Thanks @phryneas! - The incremental delivery (@defer support) implementation is now pluggable.
ApolloClient now per default ships without an incremental format implementation
and allows you to swap in the format that you want to use.
Usage looks like this:
import {
// this is the default
NotImplementedHandler,
// this implements the `@defer` transport format that ships with Apollo Router
Defer20220824Handler,
// this implements the `@defer` transport format that ships with GraphQL 17.0.0-alpha.2
GraphQL17Alpha2Handler,
} from "@apollo/client/incremental";
const client = new ApolloClient({
cache: new InMemoryCache({
/*...*/
}),
link: new HttpLink({
/*...*/
}),
incrementalHandler: new Defer20220824Handler(),
});
We will add handlers for other response formats that can be swapped this way during the lifetime of Apollo Client 4.0.
#12673 cee90ab Thanks @phryneas! - The includeExtensions option of HttpLink and BatchHttpLink now defaults
to true.
If includeExtensions is true, but extensions is not set or empty, extensions
will not be included in outgoing requests.
#12673 cee90ab Thanks @phryneas! - The ApolloClient constructor options name and version that are used to
configure the client awareness feature have moved onto a clientAwareness key.
const client = new ApolloClient({
// ..
- name: "my-app",
- version: "1.0.0",
+ clientAwareness: {
+ name: "my-app",
+ version: "1.0.0",
+ },
});
#12690 5812759 Thanks @phryneas! - Aliasing any other field to __typename is now forbidden.
#12690 5812759 Thanks @phryneas! - Aliasing a field to an alias beginning with __ac_ is now forbidden - this namespace is now reserved for internal use.
#12673 cee90ab Thanks @phryneas! - Adds enhanced client awareness to the client.
HttpLink and BatchHttpLink will now per default send information about the
client library you are using in extensions.
This could look like this:
{
"query": "query GetUser($id: ID!) { user(id: $id) { __typename id name } }",
"variables": {
"id": 5
},
"extensions": {
"clientLibrary": {
"name": "@apollo/client",
"version": "4.0.0"
}
}
}
This feature can be disabled by passing enhancedClientAwareness: { transport: false } to your
ApolloClient, HttpLink or BatchHttpLink constructor options.
#12698 be77d1a Thanks @phryneas! - Adjusted the accept header for multipart requests according to the new GraphQL over HTTP spec with these changes:
-multipart/mixed;boundary=graphql;subscriptionSpec=1.0,application/json
+multipart/mixed;boundary=graphql;subscriptionSpec=1.0,application/graphql-response+json,application/json;q=0.9
-multipart/mixed;deferSpec=20220824,application/json
+multipart/mixed;deferSpec=20220824,application/graphql-response+json,application/json;q=0.9
#12673 cee90ab Thanks @phryneas! - Add the new ClientAwarenessLink.
This link is already included in HttpLink and BatchHttpLink to enable the
"client awareness" and "enhanced client awareness" features, but you can also use
ClientAwarenessLink directly in your link chain to combine it with other
terminating links.
If you want to save the bundle size that ClientAwarenessLink adds to HttpLink
and BatchHttpLink, you can use BaseHttpLink or BaseBatchHttpLink instead.
These links come without the ClientAwarenessLink included.
For example:
import {
ApolloClient,
- HttpLink,
} from "@apollo/client";
+import { BaseHttpLink } from "@apollo/client/link/http";
const client = new ApolloClient({
- link: new HttpLink({
+ link: new BaseHttpLink({
uri,
}),
cache: new InMemoryCache(),
});
#12698 be77d1a Thanks @phryneas! - Adds an accept option to HttpOptions that allows to add additional Accept headers to be merged in without overriding user-specified or default accept headers.
#12686 dc4b1d0 Thanks @jerelmiller! - A @defer query that has not yet finished streaming is now considered loading and thus the loading flag will be true until the response has completed. A new NetworkStatus.streaming value has been introduced and will be set as the networkStatus while the response is streaming.
#12685 3b74800 Thanks @jerelmiller! - Remove the check and warning for cache.fragmentMatches when applying data masking. cache.fragmentMatches is a required API and data masking may crash when cache.fragmentMatches does not exist.
#12684 e697431 Thanks @jerelmiller! - Remove context from useLazyQuery hook options. If used, context must now be provided to the execute function. context will reset to {} if not provided as an option to execute.
#12675 8f1d974 Thanks @phryneas! - ObservableQuery no longer has a queryId property.
ApolloClient.getObservableQueries no longer returns a Map<string, ObservableQuery>, but a Set<ObservableQuery>.
#12647 a70fac6 Thanks @phryneas! - ObservableQuerys will now only be registered with the ApolloClient while they
have subscribers.
That means that ApolloClient.getObservableQueries and ApolloClient.refetchQueries
will only be able to return/refetch queries that have at least one subscriber.
This changes the previous meaning of active and inactive queries:
inactive queries are queries with a subscriber that are skipped from a
React hook or have a fetchPolicy of standbyactive queries are queries with at least one subscriber that are not skipped or in standby.ObservableQuerys without subscribers but with an active ongoing network request
(e.g. caused by calling reobserve) will be handled as if they had a subscriber
for the duration of the query.
#12678 91a876b Thanks @jerelmiller! - queryRefs created by preloadQuery no longer have a .toPromise() function. Instead preloadQuery now has a toPromise function that accepts a queryRef and will resolve when the underlying promise has been resolved.
const queryRef = preloadQuery(query, options);
- await queryRef.toPromise();
+ await preloadQuery.toPromise(queryRef);
#12647 a70fac6 Thanks @phryneas! - ApolloClient.stop() now cleans up more agressively to prevent memory leaks:
ObservableQuery instances by emitting a completed event."QueryManager stopped while query was in flight".01512f2 Thanks @jerelmiller! - Unsubscribing from an ObservableQuery before a value has been emitted will remove the query from the tracked list of queries and will no longer be eligible for query deduplication.#12663 01512f2 Thanks @jerelmiller! - Subscriptions created by client.subscribe() can now be restarted. Restarting a subscription will terminate the connection with the link chain and recreate the request. Restarts also work across deduplicated subscriptions so calling restart on an observable who's request is deduplicated will restart the connection for each observable.
const observable = client.subscribe({ query: subscription });
// Restart the connection to the link
observable.restart();
#12663 01512f2 Thanks @jerelmiller! - Deduplicating subscription operations is now supported. Previously it was possible to deduplicate a subscription only if the new subscription was created before a previously subscribed subscription emitted any values. As soon as a value was emitted from a subscription, new subscriptions would create new connections. Deduplication is now active for as long as a subscription connection is open (i.e. the source observable hasn't emitted a complete or error notification yet.)
To disable deduplication and force a new connection, use the queryDeduplication option in context like you would a query operation.
As a result of this change, calling the restart function returned from useSubscription will now restart the connection on deduplicated subscriptions.
#12670 0a880ea Thanks @phryneas! - Provide a mechanism to override the DataMasking types.
Up until now, our types Masked, MaskedDocumentNode, FragmentType, MaybeMasked and Unmasked would assume that you are stictly using the type output format of GraphQL Codegen.
With this change, you can now modify the behaviour of those types if you use a different form of codegen that produces different types for your queries.
A simple implementation that would override the Masked type to remove all fields starting with _ from a type would look like this:
// your actual implementation of `Masked`
type CustomMaskedImplementation<TData> = {
[K in keyof TData as K extends `_${string}` ? never : K]: TData[K];
};
import { HKT } from "@apollo/client/utilities";
// transform this type into a higher kinded type that can be evaulated at a later time
interface CustomMaskedType extends HKT {
arg1: unknown; // TData
return: CustomMaskedImplementation<this["arg1"]>;
}
// create an "implementation interface" for the types you want to override
export interface CustomDataMaskingImplementation {
Masked: CustomMaskedType;
// other possible keys: `MaskedDocumentNode`, `FragmentType`, `MaybeMasked` and `Unmasked`
}
then you would use that CustomDataMaskingImplementation interface in your project to extend the DataMasking interface exported by @apollo/client with it's functionality:
declare module "@apollo/client" {
export interface DataMasking extends CustomDataMaskingImplementation {}
}
After that, all internal usage of Masked in Apollo Client as well as all usage in your code base will use the new CustomMaskedType implementation.
If you don't specify overrides, Apollo Client will still default to the GraphQL Codegen data masking implementation.
The types for that are also explicitly exported as the GraphQLCodegenDataMasking namespace in @apollo/client/masking.
#12649 0be92ad Thanks @jerelmiller! - The TData generic provided to types that return a dataState property is now modified by the given DataState generic instead of passing a modified TData type. For example, a QueryRef that could return partial data was defined as QueryRef<DeepPartial<TData>, TVariables>. Now TData should be provided unmodified and a set of allowed states should be given instead: QueryRef<TData, TVariables, 'complete' | 'streaming' | 'partial'>.
To migrate, use the following guide to replace your type with the right set of states (all types listed below are changed the same way):
- QueryRef<TData, TVariables>
// `QueryRef`'s default is 'complete' | 'streaming' so this can also be left alone if you prefer
// All other types affected by this change default to all states
+ QueryRef<TData, TVariables>
+ QueryRef<TData, TVariables, 'complete' | 'streaming'>
- QueryRef<TData | undefined, TVariables>
+ QueryRef<TData, TVariables, 'complete' | 'streaming' | 'empty'>
- QueryRef<DeepPartial<TData>, TVariables>
+ QueryRef<TData, TVariables, 'complete' | 'streaming' | 'partial'>
- QueryRef<DeepPartial<TData> | undefined, TVariables>
+ QueryRef<TData, TVariables, 'complete' | 'streaming' | 'partial' | 'empty'>
The following types are affected. Provide the allowed dataState values to the TDataState generic:
ApolloQueryResultQueryRefPreloadedQueryRefuseLazyQuery.ResultuseQuery.ResultuseReadQuery.ResultuseSuspenseQuery.ResultAll *QueryRef types default to complete | streaming states while the rest of the types default to 'complete' | 'streaming' | 'partial' | 'empty' states. You shouldn't need to provide the states unless you need to either allow for partial data/empty values (*QueryRef) or a restricted set of states.
#12649 0be92ad Thanks @jerelmiller! - Remove the deprecated QueryReference type. Please use QueryRef instead.
#12633 9bfb51f Thanks @phryneas! - If the execute function of useLazyQuery is executed, previously started queries
from the same useLazyQuery usage will be rejected with an AbortError unless
.retain() is called on the promise returned by previous execute calls.
Please keep in mind that useLazyQuery is primarily meant as a means to synchronize
your component to the status of a query and that it's purpose it not to make a
series of network calls.
If you plan on making a series of network calls without the need to synchronize
the result with your component, consider using ApolloClient.query instead.
#12633 9bfb51f Thanks @phryneas! - ObservableQuery.refetch and ObservableQuery.reobserve and the execute function of useLazyQuery now return a
ResultPromise with an additional .retain method.
If this method is called, the underlying network operation will be kept running even if the ObservableQuery itself does
not require the result anymore, and the Promise will resolve with the final result instead of resolving with an intermediate
result in the case of early cancellation.
#12649 0be92ad Thanks @jerelmiller! - Add a new dataState property that determines the completeness of the data property. dataState helps narrow the type of data. dataState is now emitted from ObservableQuery and returned from all React hooks that return a data property.
The dataState values are:
empty: No data could be fulfilled from the cache or the result is incomplete. data is undefined.partial: Some data could be fulfilled from the cache but data is incomplete. This is only possible when returnPartialData is true.streaming: data is incomplete as a result of a deferred query and the result is still streaming in.complete: data is a fully satisfied query result fulfilled either from the cache or network.Example:
const { data, dataState } = useQuery<TData>(query);
if (dataState === "empty") {
expectTypeOf(data).toEqualTypeOf<undefined>();
}
if (dataState === "partial") {
expectTypeOf(data).toEqualTypeOf<DeepPartial<TData>>();
}
if (dataState === "streaming") {
expectTypeOf(data).toEqualTypeOf<TData>();
}
if (dataState === "complete") {
expectTypeOf(data).toEqualTypeOf<TData>();
}
#12644 fe2f005 Thanks @jerelmiller! - Replace the result property on ServerError with bodyText. bodyText is set to the raw string body. HttpLink and BatchHttpLink no longer try and parse the response body as JSON when a ServerError is thrown.
#12644 fe2f005 Thanks @jerelmiller! - More strictly adhere to the GraphQL over HTTP spec. This change adds support for the application/graphql-response+json media type and modifies the behavior of the application/json media type.
content-type using application/graphql-response+json with a non-200 status code.ServerError when the server encodes content-type using application/json and returns a non-200 status code.ServerError when the server encodes using any other content-type and returns a non-200 status code.NOTE: If you use a testing utility to mock requests in your test, you may experience different behavior than production if your testing utility responds as application/json but your production server responds as application/graphql-response+json. If a content-type header is not set, the client interprets the response as application/json.
#12644 fe2f005 Thanks @jerelmiller! - Change the default Accept header to application/graphql-response+json,application/json;q=0.9.
#12644 fe2f005 Thanks @jerelmiller! - HttpLink and BatchHttpLink no longer emit a next notification with the JSON-parsed response body when a well-formed GraphQL response is returned and a ServerError is thrown.
#12617 ea633a1 Thanks @jerelmiller! - Introduce a new GraphQL Codegen plugin aimed at creating resolver types for LocalState. This plugin is similar to @graphql-codegen/typescript-resolvers but tailored to provide types that work with LocalState.
To use the plugin, install @apollo/client-graphql-codegen and add the following to your codegen config:
// codegen.ts
const config: CodegenConfig = {
// ...
generates: {
"./path/to/local/resolvers.ts": {
schema: ["./path/to/localSchema.graphql"],
plugins: ["typescript", "@apollo/client-graphql-codegen/local-state"],
// ...
},
},
};
This will generate a Resolvers type in the generated file that can be used to provide type information to LocalState.
import type { Resolvers } from "./path/to/resolvers-types.ts";
const localState = new LocalState<Resolvers>({
// ...
});
It is also recommended to add the following config:
// codegen.ts
import type { LocalStatePluginConfig } from "@apollo/client-graphql-codegen/local-state";
const config: CodegenConfig = {
// ...
generates: {
"./path/to/local/resolvers.ts": {
config: {
// Ensures you return a `__typename` for any `@client` fields that
// return object or array types
nonOptionalTypename: true,
// Required if your localSchema extends existing schema types.
baseTypesPath: "./relative/path/to/base/schema/types",
// If you provide a `context` function to customize the context value,
// provide the path or type here.
contextType: "./path/to/contextValue#ContextValue",
} satisfies LocalStatePluginConfig,
},
},
};
NOTE: It is recommended that the schema file passed to the schema option is your local schema, not your entire app schema in order to only generate resolver types for your local fields, otherwise the plugin will generate resolver types for your entire remote schema as well.
#12639 1bdf489 Thanks @jerelmiller! - Move internal testing utilities in @apollo/client/testing to @apollo/client/testing/internal and remove deprecated testing utilities. Some of the testing utilities exported from the @apollo/client/testing endpoint were not considered stable. As a result of this change, testing utilities or types exported from @apollo/client/testing are now considered stable and will not undergo breaking changes.
The following APIs were removed. To migrate, update usages of the following APIs as such:
createMockClient
- const client = createMockClient(data, query, variables);
+ const client = new ApolloClient({
+ cache: new InMemoryCache(),
+ link: new MockLink([
+ {
+ request: { query, variables },
+ result: { data },
+ }
+ ]),
+ });
mockObservableLink
- const link = mockObservableLink();
+ const link = new MockSubscriptionLink();
mockSingleLink
- const link = mockSingleLink({
- request: { query, variables },
- result: { data },
- });
+ const link = new MockLink([
+ {
+ request: { query, variables },
+ result: { data },
+ }
+ ]);
#12637 d2a60d4 Thanks @phryneas! - useQuery: only advance previousData if data actually changed
#12631 b147cac Thanks @phryneas! - ObservableQuery will now return a loading: false state for fetchPolicy standby, even before subscription
#12639 1bdf489 Thanks @jerelmiller! - Remove the @apollo/client/testing/core entrypoint in favor of @apollo/client/testing.
#12639 1bdf489 Thanks @jerelmiller! - Move MockLink types to MockLink namespace. This affects the MockedResponse, MockLinkOptions, and ResultFunction types. These types are still exported but are deprecated in favor of the namespace. To migrate, use the types on the MockLink namespace instead.
import {
- MockedResponse,
- MockLinkOptions,
- ResultFunction,
+ MockLink
} from "@apollo/client/testing";
- const mocks: MockedResponse = [];
+ const mocks: MockLink.MockedResponse = [];
- const result: ResultFunction = () => {/* ... */ }
+ const result: MockLink.ResultFunction = () => {/* ... */ }
- const options: MockLinkOptions = {}
+ const options: MockLink.Options = {}
#12614 d2851e2 Thanks @jerelmiller! - The getCacheKey function is no longer available from operation.getContext() in the link chain. Use operation.client.cache.identify(obj) in the link chain instead.
#12556 c3fceda Thanks @phryneas! - ObservableQuery will now keep previous data around when emitting a loading state, unless query or variables changed.
Note that @exports variables are not taken into account for this, so data will stay around even if they change.
#12556 c3fceda Thanks @phryneas! - Removed getLastResult, getLastError and resetLastResults from ObservableQuery
#12614 d2851e2 Thanks @jerelmiller! - Removes the resolvers option from ApolloClient. Local resolvers have instead been moved to the new LocalState instance which is assigned to the localState option in ApolloClient. To migrate, move the resolvers values into a LocalState instance and assign that instance to localState.
new ApolloClient({
- resolvers: { /* ... */ }
+ localState: new LocalState({
+ resolvers: { /* ... */ }
+ }),
});
#12614 d2851e2 Thanks @jerelmiller! - Remove local resolvers APIs from ApolloClient in favor of localState. Methods removed are:
addResolversgetResolverssetResolverssetLocalStateFragmentMatcher#12614 d2851e2 Thanks @jerelmiller! - Third-party caches must now implement the fragmentMatches API. Additionally fragmentMatches must be able to handle both InlineFragmentNode and FragmentDefinitionNode nodes.
class MyCache extends ApolloCache {
// This is now required
public fragmentMatches(
fragment: InlineFragmentNode | FragmentDefinitionNode,
typename: string
): boolean {
return; // ... logic to determine if typename matches fragment
}
}
#12556 c3fceda Thanks @phryneas! - Reworked the logic for then a loading state is triggered. If the link chain responds synchronously, a loading state will be omitted, otherwise it will be triggered.
If local resolvers are used, the time window for "sync vs async" starts as soon as @exports variables are resolved.
#12556 c3fceda Thanks @phryneas! - Dropped the saveAsLastResult argument from ObservableQuery.getCurrentResult
#12614 d2851e2 Thanks @jerelmiller! - The resolver function's context argument (the 3rd argument) has changed to provide additional information without the possibility of name clashes. Previously the context argument would spread request context and override the client and cache properties to give access to both inside of a resolver. The context argument takes now takes the following shape:
{
// the request context. By default `TContextValue` is of type `DefaultContext`,
// but can be changed if a `context` function is provided.
requestContext: TContextValue,
// The client instance making the request
client: ApolloClient,
// Whether the resolver is run as a result of gathering exported variables
// or resolving the value as part of the result
phase: "exports" | "resolve"
}
To migrate, pull any request context from requestContext and the cache from the client property:
new LocalState({
resolvers: {
Query: {
- myResolver: (parent, args, { someValue, cache }) => {
+ myResolver: (parent, args, { requestContext, client }) => {
+ const someValue = requestContext.someValue;
+ const cache = client.cache;
}
}
}
});
#12614 d2851e2 Thanks @jerelmiller! - Apollo Client no longer ships with support for @client fields out-of-the-box and now must be opt-in. To opt in to use @client fields, pass an instantiated LocalState instance to the localState option. If a query contains @client and local state hasn't been configured, an error will be thrown.
import { LocalState } from "@apollo/client/local-state";
new ApolloClient({
localState: new LocalState(),
});
#12614 d2851e2 Thanks @jerelmiller! - Remove the fragmentMatcher option from ApolloClient. Custom fragment matchers used with local state are no longer supported. Fragment matching is now performed by the configured cache via the cache.fragmentMatches API.
#12556 c3fceda Thanks @phryneas! - A call to ObservableQuery.setVariables with different variables or a ObservableQuery.refetch call will always now guarantee that a value will be emitted from the observable, even if it is deep equal to the previous value.
#12614 d2851e2 Thanks @jerelmiller! - Revamp local resolvers and fix several issues from the existing resolvers option.
null and add an error to the response's errors array.context function that you can use to customize the requestContext given to resolvers.LocalState class accepts a Resolvers generic that provides autocompletion and type checking against your resolver types to ensure your resolvers are type-safe.data: null is now handled correctly and does not call your local resolvers when the server does not provide a result.import { LocalState } from "@apollo/client/local-state";
import { Resolvers } from "./path/to/local-resolvers-types.ts";
// LocalState now accepts a `Resolvers` generic.
const localState = new LocalState<Resolvers>({
// The return value of this funciton
context: (options) => ({
// ...
}),
resolvers: {
// ...
},
});
// You may also pass a `ContextValue` generic used to ensure the `context`
// function returns the correct type. This type is inferred from your resolvers
// if not provided.
new LocalState<Resolvers, ContextValue>({
// ...
});
#12600 34ff6aa Thanks @jerelmiller! - Move most of the utilities in @apollo/client/utilities to @apollo/client/utilities/internal. Many of the utilities exported from the @apollo/client/utilities endpoint were not considered stable.
As a result of this change, utilities or types exported from @apollo/client/utilities are now documented and considered stable and will not undergo breaking changes.
#12595 60bb49c Thanks @jerelmiller! - Remove the @apollo/client/testing/experimental test utilities. Use GraphQL Testing Library instead.
e4a3ecf Thanks @jerelmiller! - Remove code that strips @client fields in HttpLink and BatchHttpLink. This was unused code since core handles removing @client fields and should have no observable change.#12586 605db8e Thanks @jerelmiller! - Remove the typeDefs option from ApolloClient.
#12588 eed825a Thanks @jerelmiller! - Remove TContext generic argument from all types that use it. TContext is replaced with DefaultContext which can be modified using declaration merging.
#12590 a005e82 Thanks @jerelmiller! - Drop graphql v15 as a valid peer dependency.
#12591 a7e7383 Thanks @jerelmiller! - Rename the @apollo/client/link/core entrypoint to @apollo/client/link.
#12589 15f5a1c Thanks @jerelmiller! - Require the link option when instantiating ApolloClient. This removes the uri, credentials and headers options from ApolloClient in favor of passing an instantiated HttpLink directly. To migrate:
If using uri, credentials, or headers options
new ApolloClient({
// ...
- uri,
- credentials,
- headers,
+ link: new HttpLink({ uri, credentials, headers }),
// or if you prefer the function call approach:
+ link: createHttpLink({ uri, credentials, headers }),
});
If creating a client without the link option
new ApolloClient({
// ...
+ link: ApolloLink.empty()
});