NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
npm · #4032 most downloaded on npm
A fully-featured caching GraphQL client.
Last release 2 days ago
18 Sep 2026
Ships fairly regularly
a new release about every 2 weeks
Nearly every release is documented
notes for 60 of the last 60 stable releases
27 versions withdrawn
withdrawn after publishing
7 years old
727 releases · first in 2019
When a read function is not defined nor is there a defined resolver for the field, warn and set the value to null only in that instance.
#12934 54ab6d9 Thanks @jerelmiller! - Don't set the fallback value of a @client field to null when a read function is defined. Instead the read function will be called with an existing value of undefined to allow default arguments to be used to set the returned value.
When a read function is not defined nor is there a defined resolver for the field, warn and set the value to null only in that instance.
#12934 54ab6d9 Thanks @jerelmiller! - Add an abstract resolvesClientField function to ApolloCache that can be used by caches to tell LocalState if it can resolve a @client field when a local resolver is not defined.
LocalState will emit a warning and set a fallback value of null when no local resolver is defined and resolvesClientField returns false, or isn't defined. Returning true from resolvesClientField signals that a mechanism in the cache will set the field value. In this case, LocalState won't set the field value.
#12915 c97b145 Thanks @phryneas! - Create mechanism to add experimental features to Apollo Client
#12934 54ab6d9 Thanks @jerelmiller! - Ensure LocalState doesn't try to read from the cache when using a no-cache fetch policy.
#12934 54ab6d9 Thanks @jerelmiller! - Warn when using a no-cache fetch policy without a local resolver defined. no-cache queries do not read or write to the cache which meant no-cache queries are silently incomplete when the @client field value was handled by a cache read function.
One column per quarter.
```ts import { GraphQL17Alpha9Handler } from "@apollo/client/incremental";
#12923 2aa31c7 Thanks @jerelmiller! - Fix an issue where deferred payloads that reteurned arrays with fewer items than the original cached array would retain items from the cached array. This change includes @stream arrays where stream arrays replace the cached arrays.
#12926 c7fba99 Thanks @jerelmiller! - Support the newer incremental delivery format for the @defer directive implemented in graphql@17.0.0-alpha.9. Import the GraphQL17Alpha9Handler to use the newer incremental delivery format with @defer.
import { GraphQL17Alpha9Handler } from "@apollo/client/incremental";
const client = new ApolloClient({
// ...
incrementalHandler: new GraphQL17Alpha9Handler(),
});
[!NOTE] In order to use the
GraphQL17Alpha9Handler, the GraphQL server MUST implement the newer incremental delivery format. You may see errors or unusual behavior if you use the wrong handler. If you are using Apollo Router, continue to use theDefer20220824Handlerbecause Apollo Router does not yet support the newer incremental delivery format.
#12918 562e219 Thanks @jerelmiller! - Add support for the @stream directive on both the Defer20220824Handler and the GraphQL17Alpha2Handler.
[!NOTE] The implementations of
@streamdiffer in the delivery of incremental results between the different GraphQL spec versions. If you upgrading from the older format to the newer format, expect the timing of some incremental results to change.
#12925 f538a83 Thanks @jerelmiller! - Fix an issue where calling fetchMore with @defer or @stream would not rerender incremental results as they were streamed.
#12923 01cace0 Thanks @jerelmiller! - Improve the cache data loss warning message when existing or incoming is an array.
This fixes an issue where the change introduced in 4.0.11 via #13049 would not be applied if defaultOptions for watchQuery were declared.
#13094 9cbe2c2 Thanks @phryneas! - Ensure that compact and mergeOptions preserve symbol keys.
This fixes an issue where the change introduced in 4.0.11 via #13049 would not
be applied if defaultOptions for watchQuery were declared.
Please note that compact and mergeOptions are considered internal utilities
and they might have similar behavior changes in future releases.
Do not use them in your application code - a change like this is not considered
breaking and will not be announced as such.
### Patch Changes - #13077 `f322460` Thanks @phryneas! - Fix a potential memory leak where Trie nodes would remain in memory too long.
### Patch Changes - #12884 `d329790` Thanks @phryneas! - Ensure that PreloadedQueryRef instances are unsubscribed when garbage collected - #13069 `9ca
These queries are now properly excluded from refetch operations until after their initial execution.
#13050 8020829 Thanks @phryneas! - Replace usage of findLast with more backwards-compatible methods.
#13049 05638de Thanks @phryneas! - Fixes an issue where queries starting with skipToken or lazy queries from useLazyQuery were included in client.refetchQueries() before they had been executed for the first time. While generally queries with a standby fetchPolicy should be included in refetch, these queries never had variables passed in, so they should be excluded until they have run once and received their actual variables.
These queries are now properly excluded from refetch operations until after their initial execution.
This change adds a new hidden option to client.watchQuery, [variablesUnknownSymbol], which may be set true for queries starting with a fetchPolicy of standby. It will only be applied when creating the ObservableQuery instance and cannot be changed later. This flag indicates that the query's variables are not yet known, and thus it should be excluded from refetch operations until they are.
This option is not meant for everyday use and is intended for framework integrations only.
### Patch Changes - #13045 `af4acdc` Thanks @phryneas! - Fix memory leak #13036
### Patch Changes - #12993 `8f3bc9b` Thanks @jerelmiller! - Fix an issue where switching from options with variables to skipToken with useSuspenseQuer
8f3bc9b Thanks @jerelmiller! - Fix an issue where switching from options with variables to skipToken with useSuspenseQuery and useBackgroundQuery would create a new ObservableQuery. This could cause unintended refetches where variables were absent in the request when the query was referenced with refetchQueries.### Patch Changes - #12983 `f6d0efa` Thanks @CarsonF! - Fix cache.modify() mapping readonly arrays to singular reference
### Patch Changes - #12950 `5b4f36a` Thanks @jerelmiller! - Don't send operationType in the payload sent by GraphQLWsLink.
5b4f36a Thanks @jerelmiller! - Don't send operationType in the payload sent by GraphQLWsLink.### Patch Changes - #12937 `3b0d89b` Thanks @phryneas! - Fix a problem with fetchMore where the loading state wouldn't reset if the result wouldn't re
### Patch Changes - #12920 `e2fc385` Thanks @phryneas! - Fix an invariance type error in the MockedResponse type.
```ts import { skipToken, useQuery } from "@apollo/client/react";
#12892 db8a04b Thanks @jerelmiller! - Prevent unhandled rejections from the promise returned by calling the mutate function from the useMutation hook.
#12899 5352c12 Thanks @phryneas! - Fix an issue when invariant is called by external libraries when no dev error message handler is loaded.
#12895 71f2517 Thanks @jerelmiller! - Support skipToken with useQuery to provide a more type-safe way to skip query execution.
import { skipToken, useQuery } from "@apollo/client/react";
// Use `skipToken` in place of `skip: true` for better type safety
// for required variables
const { data } = useQuery(QUERY, id ? { variables: { id } } : skipToken);
Note: this change is provided as a patch within the 4.0 minor version because the changes to TypeScript validation with required variables in version 4.0 made using the skip option more difficult.
#12900 c0d5be7 Thanks @phryneas! - Use named export equal instead of default from "@wry/equality"
### Patch Changes - #12887 `6f6ca47` Thanks @phryneas! - Fix accidental deep re-export from /react out of /react/internals - #12890 `019b422` Thanks @
### Patch Changes - #12880 `56fac52` Thanks @phryneas! - restore getMemoryInternals access in dev builds
### Patch Changes - #12876 `b00f231` Thanks @phryneas! - Fix CJS build output for invariantErrorCodes - #12866 `0d1614a` Thanks @jerelmiller! - Export
…and considered stable and will not undergo breaking changes.
Apollo Client 4.0 delivers a more modern, efficient, and type-safe GraphQL client experience through various architectural improvements and API refinements. This release focuses on developer experience, bundle size optimization, and framework flexibility.
Apollo Client 4.0 separates React functionality from the core library, making @apollo/client truly framework-agnostic. React exports now live in @apollo/client/react, allowing developers to use Apollo Client with any JavaScript framework without React dependencies.
@client directive functionality is now opt-in via the LocalState class, reducing bundle size when not using local statesince 2023, node >= 20, not dead, leveraging modern JavaScript features for better performanceexports field in package.json enables better dead code eliminationApollo Client 4.0 completely reimagines error handling for better clarity and debugging:
ApolloError removed in favor of specific error classeserror propertyerrorPolicy settings.is() methods for robust type narrowinguseQuery.Options instead of QueryHookOptions)returnPartialData makes data type DeepPartial<TData>)dataState Property: Enables accurate type narrowing of query resultsgql.tadaApollo Client 4.0 migrates from zen-observable to RxJS, providing the industry-standard Observable implementation backed by a rich ecosystem of utilities.
Apollo Client 4.0 completely reimagines error handling for better clarity and debugging:
Key Changes:
ApolloError removed in favor of specific error classeserrorPolicy settings.is() methods for type checkingError Classes:
CombinedGraphQLErrors - GraphQL errors from the serverServerError - Non-GraphQL server errorsServerParseError - Server response parsing errorsUnconventionalError - Wrapper for non-error thrown valuesLinkError - Errors from the link chain (via .is() check)Migration Example:
// Apollo Client 3
if (error instanceof ApolloError) {
console.log(error.graphQLErrors);
console.log(error.networkError);
}
// Apollo Client 4
import { CombinedGraphQLErrors } from "@apollo/client";
if (CombinedGraphQLErrors.is(error)) {
console.log(error.errors); // GraphQL errors
} else if (error) {
console.log(error.message); // Other errors
}
dataState PropertyA new property that clearly indicates the completeness of query results:
Values:
empty - No data available (data is undefined)partial - Incomplete data from cache when returnPartialData is truestreaming - Incomplete data from a deferred query still streamingcomplete - Fully satisfied query resultBenefits:
const { data, dataState } = useQuery(MY_QUERY);
if (dataState === "complete") {
// TypeScript knows data is fully populated
console.log(data.allFields);
} else if (dataState === "partial") {
// TypeScript knows data might be missing fields
console.log(data?.someField);
}
@defer Support)Apollo Client 4.0 makes incremental delivery configurable and future-proof:
import { Defer20220824Handler } from "@apollo/client/incremental";
const client = new ApolloClient({
// ...
incrementalHandler: new Defer20220824Handler(),
});
Available Handlers:
NotImplementedHandler - Default, throws if @defer is usedDefer20220824Handler - Apollo Router format support (also aliased as GraphQL17Alpha2Handler)Local state is now opt-in via the LocalState class:
import { LocalState } from "@apollo/client/local-state";
const client = new ApolloClient({
cache,
localState: new LocalState({
resolvers: {
Query: {
myField: () => "Hello World",
},
},
}),
});
Resolver Context Changes:
// Apollo Client 3
const resolver = (parent, args, context, info) => {
const { cache } = context;
};
// Apollo Client 4
const resolver = (parent, args, context, info) => {
const { client, requestContext, phase } = context;
const cache = client.cache;
};
useLazyQuery Overhaul:
variables or context options (pass to execute instead)execute function only accepts variables and contextuseMutation Changes:
ignoreResults option - use client.mutate directly for fire-and-forget mutationsuseQuery Changes:
notifyOnNetworkStatusChange now defaults to trueonCompleted and onError callbacksThe new prerenderStatic API replaces deprecated SSR functions:
import { prerenderStatic } from "@apollo/client/react/ssr";
// Works with React 19's prerender APIs
const html = await prerenderStatic(<App />, {
client,
});
Pre-compiled React hooks optimized by the React Compiler:
// Use compiled hooks for potential performance improvements
import { useQuery } from "@apollo/client/react/compiled";
The compiled hooks are built with React Compiler v19.1.0-rc.2 and include a runtime polyfill for compatibility with React 17+.
Migration from creator functions to classes:
// Apollo Client 3
import { createHttpLink, setContext } from "@apollo/client";
const httpLink = createHttpLink({ uri: "/graphql" });
const authLink = setContext((operation, prevContext) => {
/*...*/
});
// Apollo Client 4
import { HttpLink, SetContextLink } from "@apollo/client";
const httpLink = new HttpLink({ uri: "/graphql" });
const authLink = new SetContextLink((prevContext, operation) => {
/*...*/
});
// Apollo Client 3
onError(({ graphQLErrors, networkError }) => {
// Handle errors separately
});
// Apollo Client 4
new ErrorLink(({ error }) => {
if (CombinedGraphQLErrors.is(error)) {
// Handle GraphQL errors
} else if (error) {
// Handle other errors
}
});
Apollo Client 4.0 provides a comprehensive codemod to automate migration:
# Basic usage
npx @apollo/client-codemod-migrate-3-to-4 src
# TypeScript projects (run separately)
npx @apollo/client-codemod-migrate-3-to-4 --parser ts --extensions ts src
npx @apollo/client-codemod-migrate-3-to-4 --parser tsx --extensions tsx src
The codemod handles:
@apollo/client/react@apollo/client/v4-migration with migration instructions# RxJS is now a peer dependency
npm install @apollo/client graphql rxjs
link option is now required (no more implicit HttpLink creation)uri, headers, credentials removed - use HttpLink directlyname and version moved to clientAwareness optionresolvers moved to LocalState constructorconnectToDevTools replaced with devtools.enableddisableNetworkFetches renamed to prioritizeCacheValuesTContext and TCacheShape generics.pipe() for transformationsMockedProvider now has realistic delays by default (20-50ms)createMockClient removed - use MockLink directly__DEV__exports field for better module resolution@apollo/client/react/components)@apollo/client/react/hoc)@apollo/client/react/parser@apollo/client/utilities/globalsnpm install rxjsHttpLink, LocalState if needed)Apollo Client 4.0 represents years of community feedback and contributions. Thank you to all our contributors, early adopters, and the entire GraphQL community for making this release possible.
<details>
<summary>
</summary>
#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.
#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.
#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.
#12539 dd0d6d6 Thanks @jerelmiller! - onError link now uses a single error property to report the error that caused the link callback to be called. This will be an instance of CombinedGraphQLErrors in the event GraphQL errors were emitted from the terminating link, CombinedProtocolErrors if the terminating link emitted protocol errors, or the unwrapped error type if any other non-GraphQL error was thrown or emitted.
- const errorLink = onError(({ graphQLErrors, networkError, protocolErrors }) => {
- graphQLErrors.forEach(error => console.log(error.message));
+ const errorLink = onError(({ error }) => {
+ if (error.name === 'CombinedGraphQLErrors') {
+ error.errors.forEach(rawError => console.log(rawError.message));
+ }
});
#12586 605db8e Thanks @jerelmiller! - Remove the typeDefs option from ApolloClient.
#12384 6aa6fd3 Thanks @jerelmiller! - Remove the asyncMap utility function. Instead use one of the RxJS operators that creates Observables from promises, such as from.
#12398 8cf5077 Thanks @jerelmiller! - Removes the isApolloError utility function to check if the error object is an ApolloError instance. Use instanceof to check for more specific error types that replace ApolloError.
#12379 ef892b4 Thanks @jerelmiller! - Removes the addTypename option from InMemoryCache and MockedProvider. __typename is now always added to the outgoing query document when using InMemoryCache and cannot be disabled.
If you are using <MockedProvider /> with addTypename={false}, ensure that your mocked responses include a __typename field. This will ensure cache normalization kicks in and behaves more like production.
#12396 00f3d0a Thanks @jerelmiller! - Remove the deprecated errors property from useQuery and useLazyQuery. Read errors from the error property instead.
#12809 e2a0be8 Thanks @jerelmiller! - operation.getContext now returns a Readonly<OperationContext> type.
#12809 e2a0be8 Thanks @jerelmiller! - The ApolloLink.Request (i.e. GraphQLRequest) passed to ApolloLink.execute no longer accepts operationName and operationType options. These properties are derived from the query and set on the returned ApolloLink.Operation type.
#12712 bbb2b61 Thanks @jerelmiller! - An error is now thrown when trying to call fetchMore on a cache-only query.
#12222 d1a9054 Thanks @jerelmiller! - Drop support for React 16.
#12787 8ce31fa Thanks @phryneas! - Remove DataProxy namespace and interface.
#12450 876d070 Thanks @jerelmiller! - Remove TSerialized generic argument to ApolloCache. The ApolloCache base cache abstraction now returns unknown for cache.extract which can be overridden by a cache subclass.
#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.
#12376 a0c996a Thanks @jerelmiller! - Remove deprecated ignoreResults option from useMutation. If you don't want to synchronize component state with the mutation, use useApolloClient to access your client instance and use client.mutate directly.
#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.
#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.
#12513 9c3207c Thanks @phryneas! - Removed the @apollo/client/react/context and @apollo/client/react/hooks entry points. Please use @apollo/client/react instead.
#12384 6aa6fd3 Thanks @jerelmiller! - Unusubscribing from ObservableQuery while a request is in flight will no longer terminate the request by unsubscribing from the link observable.
#12463 3868df8 Thanks @jerelmiller! - ObservableQuery.setOptions has been removed as it was an alias of reobserve. Prefer using reobserve directly instead.
const observable = client.watchQuery(options);
// Use reobserve to set new options and reevaluate the query
- observable.setOptions(newOptions);
+ observable.reobserve(newOptions);
As a result of this change, reobserve has been marked for public use and is no longer considered an internal API. The newNetworkStatus argument has been removed to facilitate this change.
#12478 5ea6a45 Thanks @jerelmiller! - Remove variables from the result returned from useSubscription.
#12735 5159880 Thanks @jerelmiller! - Remove deprecated resultCacheMaxSize option from InMemoryCache options.
#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",
+ },
});
#12367 e6af35e Thanks @jerelmiller! - The previousData property on useLazyQuery will now change only when data changes. Previously previousData would change to the same value as data while the query was loading.
#12690 5812759 Thanks @phryneas! - Aliasing any other field to __typename is now forbidden.
#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.
#12776 bce9b74 Thanks @jerelmiller! - Report masked fragments as complete even when a nested masked fragment contains partial data.
#12788 4179446 Thanks @phryneas! - TVariables now always extends OperationVariables in all interfaces.
#12224 51e6c0f Thanks @jerelmiller! - Remove deprecated partialRefetch option.
#12407 8b1390b Thanks @jerelmiller! - Calling refetch with new variables will now set the networkStatus to refetch instead of setVariables.
#12476 6afff60 Thanks @jerelmiller! - Subscriptions now emit a SubscribeResult instead of a FetchResult. As a result, the errors field has been removed in favor of error.
#12457 32e85ea Thanks @jerelmiller! - Network errors triggered by queries now adhere to the errorPolicy. This means that GraphQL errors and network errors now behave the same way. Previously promise-based APIs, such as client.query, would reject the promise with the network error even if errorPolicy was set to ignore. The promise is now resolved with the error property set to the network error instead.
#12840 83e132a Thanks @phryneas! - If you use an incremental delivery handler, you now have to explicitly opt into adding the chunk types to the ApolloLink.Result type.
import { Defer20220824Handler } from "@apollo/client/incremental";
declare module "@apollo/client" {
export interface TypeOverrides extends Defer20220824Handler.TypeOverrides {}
}
#12712 bbb2b61 Thanks @jerelmiller! - cache-only queries are no longer refetched when calling client.reFetchObservableQueries when includeStandby is true.
#12808 8e31a23 Thanks @phryneas! - HTTP Multipart handling will now throw an error if the connection closed before the final boundary has been received.
Data after the final boundary will be ignored.
#12384 6aa6fd3 Thanks @jerelmiller! - Remove the iterateObserversSafely utility function.
#12825 292b949 Thanks @jerelmiller! - The serializeFetchParameter helper is no longer exported and JSON.stringify is used directly. As such, the ClientParseError type has also been removed in favor of throwing any JSON serialize errors directly.
#12595 60bb49c Thanks @jerelmiller! - Remove the @apollo/client/testing/experimental test utilities. Use GraphQL Testing Library instead.
#12718 ecfc02a Thanks @jerelmiller! - Version bump only to release latest as rc.
#12470 d32902f Thanks @phryneas! - ssrMode, ssrForceFetchDelay and disableNetworkFetches have been reworked:
Previously, a ObservableQuery created by client.query or client.watchQuery
while one of those were active would permanently be changed from a fetchPolicy
of "network-only" or "cache-and-network" to "cache-first", and stay that way
even long after disableNetworkFetches would have been deactivated.
Now, the ObservableQuery will keep their original fetchPolicy, but queries
made during disableNetworkFetches will just apply the fetchPolicy replacement
at request time, just for that one request.
ApolloClient.disableNetworkFetches has been renamed to ApolloClient.prioritizeCacheValues to better reflect this behaviour.
#12559 49ace0e Thanks @jerelmiller! - ObservableQuery.variables can now be reset back to empty when calling reobserve with variables: undefined. Previously the variables key would be ignored so variables would remain unchanged.
#12559 49ace0e Thanks @jerelmiller! - never is no longer supported as a valid TVariables generic argument for APIs that require variables as part of its type. Use Record<string, never> instead.
#12735 5159880 Thanks @jerelmiller! - Remove deprecated connectToDevtools option from ApolloClientOptions. Use devtools.enabled instead.
#12576 a92ff78 Thanks @jerelmiller! - The cache and forceFetch properties are no longer available on context when calling operation.getContext(). cache can be accessed through the operation with operation.client.cache instead. forceFetch has been replaced with queryDeduplication which specifies whether queryDeduplication was enabled for the request or not.
#12533 73221d8 Thanks @jerelmiller! - Remove the onError and setOnError methods from ApolloLink. onError was only used by MockLink to rewrite errors if setOnError was used.
#12485 d338303 Thanks @jerelmiller! - Throw an error for queries and mutations if the link chain completes without emitting a value.
#12556 c3fceda Thanks @phryneas! - Removed getLastResult, getLastError and resetLastResults from ObservableQuery
#12663 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.
#12809 e2a0be8 Thanks @jerelmiller! - operation.operationType is now a non-null OperationTypeNode. It is now safe to compare this value without having to check for undefined.
#12398 8cf5077 Thanks @jerelmiller! - Apollo Client no longer wraps errors in ApolloError. ApolloError has been replaced with separate error classes depending on the cause of the error. As such, APIs that return an error property have been updated to use the generic Error type. Use instanceof to check for more specific error types.
ApolloError encapsulated 4 main error properties. The type of error would determine which property was set:
graphqlErrors - Errors returned from the errors field by the GraphQL servernetworkError - Any non-GraphQL error that caused the query to failprotocolErrors - Transport-level errors that occur during multipart HTTP subscriptionsclientErrors - A space to define custom errors. Mostly unused.These errors were mutally exclusive, meaning both networkError and graphqlErrors were never set simultaneously. The following replaces each of these fields from ApolloError.
graphqlErrorsGraphQL errors are now encapsulated in a CombinedGraphQLErrors instance. You can access the raw GraphQL errors via the errors property.
import { CombinedGraphQLErrors } from "@apollo/client";
// ...
const { error } = useQuery(query);
if (error && error instanceof CombinedGraphQLErrors) {
console.log(error.errors);
}
networkErrorNetwork errors are no longer wrapped and are instead passed through directly.
const client = new ApolloClient({
link: new ApolloLink(() => {
return new Observable((observer) => {
observer.error(new Error("Test error"));
});
}),
});
// ...
const { error } = useQuery(query);
// error is `new Error('Test error')`;
protocolErrorsProtocol errors are now encapsulated in a CombinedProtocolErrors instance. You can access the raw protocol errors via the errors property.
import { CombinedProtocolErrors } from "@apollo/client";
// ...
const { error } = useSubscription(subscription);
if (error && error instanceof CombinedProtocolErrors) {
console.log(error.errors);
}
clientErrorsThese were unused by the client and have no replacement. Any non-GraphQL or non-protocol errors are now passed through unwrapped.
If the link sends a string error, Apollo Client will wrap this in an Error instance. This ensures error properties are guaranteed to be of type Error.
const client = new ApolloClient({
link: new ApolloLink(() => {
return new Observable((observer) => {
// Oops we sent a string instead of wrapping it in an `Error`
observer.error("Test error");
});
}),
});
// ...
const { error } = useQuery(query);
// The error string is wrapped and returned as `new Error('Test error')`;
If the link chain sends any other object type as an error, Apollo Client will wrap this in an UnknownError instance with the cause set to the original object. This ensures error properties are guaranteed to be of type Error.
const client = new ApolloClient({
link: new ApolloLink(() => {
return new Observable((observer) => {
observer.error({ message: "Not a proper error type" });
});
}),
});
// ...
const { error } = useQuery(query);
// error is an `UnknownError` instance. error.cause returns the original object.
#12809 e2a0be8 Thanks @jerelmiller! - operation.operationName is now set as string | undefined where undefined represents an anonymous query. Previously operationName would return an empty string as the operationName for anonymous queries.
#12450 876d070 Thanks @jerelmiller! - Remove the TCacheShape generic argument to ApolloClient. client.extract() now returns unknown by default. You will either need to type-cast this to the expected serialized shape, or use the cache.extract() directly from the subclass to get more specific types.
#12774 511b4f3 Thanks @jerelmiller! - Apply document transforms before reading data from the cache for client.readQuery, client.readFragment, client.watchFragment, useFragment, and useSuspenseFragment.
NOTE: This change does not affect the equivalent cache.* APIs. To read data from the cache without first running document transforms, run cache.readQuery, cache.readFragment, etc.
#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.
#12475 3de63eb Thanks @jerelmiller! - Unify error behavior on mutations for GraphQL errors and network errors by ensuring network errors are subject to the errorPolicy. Network errors created when using an errorPolicy of all will now resolve the promise and be returned on the error property of the result, or stripped away when the errorPolicy is none.
#12384 6aa6fd3 Thanks @jerelmiller! - Remove fromError utility function. Use throwError instead.
#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.
#12850 268cd80 Thanks @phryneas! - Introduce a versioning policy.
#12809 e2a0be8 Thanks @jerelmiller! - The concat, from, and split functions on ApollLink no longer support a plain request handler function. Please wrap the request handler with new ApolloLink.
const link = new ApolloLink(/* ... */);
link.concat(
- (operation, forward) => forward(operation),
+ new ApolloLink((operation, forward) => forward(operation)),
);
#12802 e2b51b3 Thanks @jerelmiller! - Disallow the mutation option for the mutate function returned from useMutation.
#12211 c2736db Thanks @jerelmiller! - Remove the deprecated graphql, withQuery, withMutation, withSubscription, and withApollo hoc components. Use the provided React hooks instead.
#12690 5812759 Thanks @phryneas! - Aliasing a field to an alias beginning with __ac_ is now forbidden - this namespace is now reserved for internal use.
#12559 49ace0e Thanks @jerelmiller! - When passing a variables key with the value undefined, the value will be replaced by the default value in the query, if it is provided, rather than leave it as undefined.
// given this query
const query = gql`
query PaginatedQuery($limit: Int! = 10, $offset: Int) {
list(limit: $limit, offset: $offset) {
id
}
}
`;
const observable = client.query({
query,
variables: { limit: 5, offset: 0 },
});
console.log(observable.variables); // => { limit: 5, offset: 0 }
observable.reobserve({ variables: { limit: undefined, offset: 10 } });
// limit is now `10`. This would previously be `undefined`
console.log(observable.variables); // => { limit: 10, offset: 10 }
#12262 10ef733 Thanks @jerelmiller! - Remove itAsync test utility.
#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.
#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) => {
// ...
})
#12536 e14205a Thanks @jerelmiller! - An initial loading state is now emitted from ObservableQuery when subscribing if notifyOnNetworkStatusChange is set to true.
#12465 a132163 Thanks @jerelmiller! - Flatten out React hook types. As a result, the base types have been removed. Prefer using the hook types instead. Removed types include:
BaseMutationOptionsBaseQueryOptionsBaseSubscriptionOptionsObservableQueryFieldsMutationSharedOptionsQueryFunctionOptions#12675 8f1d974 Thanks @phryneas! - ObservableQuery no longer has a queryId property.
ApolloClient.getObservableQueries no longer returns a Map<string, ObservableQuery>, but a Set<ObservableQuery>.
#12398 8cf5077 Thanks @jerelmiller! - Updates the ServerError and ServerParseError types to be proper Error subclasses. Perviously these were plain Error intances with additional properties added at runtime. All properties are retained, but instanceof checks now work correctly.
import { ServerError, ServerParseError } from "@apollo/client";
if (error instanceof ServerError) {
// ...
}
if (error instanceof ServerParseError) {
// ...
}
#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.
#12463 3868df8 Thanks @jerelmiller! - useQuery no longer returns reobserve as part of its result. It was possible to use reobserve to set new options on the underlying ObservableQuery instance which differed from the options passed to the hook. This could result in unexpected results. Instead prefer to rerender the hook with new options.
#12367 e6af35e Thanks @jerelmiller! - useLazyQuery no longer supports SSR environments and will now throw if the execute function is called in SSR. If you need to run a query in an SSR environment, use useQuery instead.
#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: { /* ... */ }
+ }),
});
#12475 3de63eb Thanks @jerelmiller! - client.mutate now returns a MutateResult instead of FetchResult. As a result, the errors property has been removed in favor of error which is set if either a network error occured or GraphQL errors are returned from the server.
useMutation now also returns a MutateResult instead of a FetchResult.
#12367 e6af35e Thanks @jerelmiller! - The execute function returned from useLazyQuery now only supports the context and variables options. This means that passing options supported by the hook no longer override the hook value.
To change options, rerender the component with new options. These options will take effect with the next query execution.
#12384 6aa6fd3 Thanks @jerelmiller! - ObservableQuery will no longer terminate on errors and will instead emit a next value with an error property. This ensures that ObservableQuery instances can continue to receive updates after errors are returned in requests without the need to resubscribe to the observable.
#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#12787 8ce31fa Thanks @phryneas! - Generic arguments for Cache.ReadOptions were flipped from TVariables, TData to TData, TVariables.
#12837 7c49fdc Thanks @jerelmiller! - You must now opt in to use GraphQL Codegen data masking types when using Apollo Client's data masking feature. By default, Apollo Client now uses an identity type to apply to masked/unmasked types.
If you're using GraphQL Codegen to generate masked types, opt into the GraphQL Codegen masked types using declaration merging on the TypeOverides interface.
import { GraphQLCodegenDataMasking } from "@apollo/client/masking";
declare module "@apollo/client" {
export interface TypeOverrides
extends GraphQLCodegenDataMasking.TypeOverrides {}
}
#12824 0506f12 Thanks @jerelmiller! - Ensure the error argument for the delay and attempts functions on RetryLink are an ErrorLike.
#12398 8cf5077 Thanks @jerelmiller! - Removes the throwServerError utility function. Now that ServerError is an
Error subclass, you can throw these errors directly:
import { ServerError } from "@apollo/client";
// instead of
throwServerError(response, result, "error message");
// Use
throw new ServerError("error message", { response, result });
#12837 7c49fdc Thanks @jerelmiller! - The types mode for data masking has been removed. Adding a types mode to the DataMasking interface has no effect. Remove the mode key in the module where you declare the DataMasking type for the @apollo/client module.
As a result, the Masked and MaskedDocumentNode types have also been removed since these have no effect when types are preserved.
#12304 86469a2 Thanks @jerelmiller! - The Cache.DiffResult<T> type is now a union type with better type safety for both complete and partial results. Checking diff.complete will now narrow the type of result depending on whether the value is true or false.
When true, diff.result will be a non-null value equal to the T generic type. When false, diff.result now reports result as DeepPartial<T> | null indicating that fields in the result may be missing (DeepPartial<T>) or empty entirely (null).
#12731 0198870 Thanks @phryneas! - Ship React Compiler compiled React hooks in @apollo/client/react/compiled.
We now ship a React-Compiler compiled version of the React hooks in
@apollo/client/react/compiled.
This entry point contains everything that @apollo/client/react does,
so you can use it as a drop-in replacement in your whole application
if you choose to use the compiled hooks.
#12446 ab920d2 Thanks @jerelmiller! - Removes the defaultOptions option from useQuery. Use options directly or use the global ApolloClient defaultOptions.
#12649 0be92ad Thanks @jerelmiller! - Remove the deprecated QueryReference type. Please use QueryRef instead.
#12396 00f3d0a Thanks @jerelmiller! - Remove the errors property from the results emitted from ObservableQuery or returned from client.query. Read errors from the error property instead.
#12367 e6af35e Thanks @jerelmiller! - The result resolved from the promise returned from the execute function in useLazyQuery is now an ApolloQueryResult type and no longer includes all the fields returned from the useLazyQuery hook tuple.
If you need access to the additional properties such as called, refetch, etc. not included in ApolloQueryResult, read them from the hook instead.
#12531 7784b46 Thanks @jerelmiller! - Mocked responses passed to MockLink now accept a callback for the request.variables option. This is used to determine if the mock should be matched for a set of request variables. With this change, the variableMatcher option has been removed in favor of passing a callback to variables. Update by moving the callback function from variableMatcher to request.variables.
new MockLink([
{
request: {
query,
+ variables: (requestVariables) => true
},
- variableMatcher: (requestVariables) => true
}
]);
#12793 24e98a1 Thanks @phryneas! - ApolloConsumer has been removed - please use useApolloClient instead.
#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.#12614 d2851e2 Thanks @jerelmiller! - Remove local resolvers APIs from ApolloClient in favor of localState. Methods removed are:
addResolversgetResolverssetResolverssetLocalStateFragmentMatcher#12576 a92ff78 Thanks @jerelmiller! - ApolloLink.execute now requires a third argument which provides the client that initiated the request to the link chain. If you use execute directly, add a third argument with a client property:
ApolloLink.execute(link, operation, { client });
// or if you import the `execute` function directly:
execute(link, operation, { client });
#12526 391af1d Thanks @phryneas! - The @apollo/client and @apollo/client/core entry points are now equal.
In the next major, the @apollo/client/core entry point will be removed.
Please change imports over from @apollo/client/core to @apollo/client.
#12700 8e96e08 Thanks @phryneas! - Added a new Streaming type that will mark data in results while dataState
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;
}
}
#12367 e6af35e Thanks @jerelmiller! - useLazyQuery will no longer rerender with the loading state when calling the execute function the first time unless the notifyOnNetworkStatusChange option is set to true (which is the new default).
If you prefer the behavior from 3.x, rerender the component with
notifyOnNetworkStatusChange set to false after the execute function is
called the first time.
function MyComponent() {
const [notifyOnNetworkStatusChange, setNotifyOnNetworkStatusChange] =
useState(true);
const [execute] = useLazyQuery(query, { notifyOnNetworkStatusChange });
async function runExecute() {
await execute();
// Set to false after the initial fetch to stop receiving notifications
// about changes to the loading states.
setNotifyOnNetworkStatusChange(false);
}
// ...
}
#12475 3de63eb Thanks @jerelmiller! - Mutations no longer report errors if the GraphQL result from the server contains an empty array of errors.
#12254 0028ac0 Thanks @jerelmiller! - Changes the default Accept header to application/graphql-response+json.
#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.
#12513 9c3207c Thanks @phryneas! - Removed the @apollo/client/react/parser entry point. There is no replacement.
#12430 2ff66d0 Thanks @jerelmiller! - ObservableQuery.setVariables will now resolve with the last emitted result instead of undefined when either the variables match the current variables or there are no subscribers to the query.
#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.
#12385 cad5117 Thanks @phryneas! - Apollo Client now defaults to production mode, not development mode, if the
environment cannot be determined.
In modern bundlers, this should automatically be handled by the bundler loading
the bundler with the development export condition.
If neither the production nor the development export condition are
used by the bundler/runtime, Apollo Client will fall back to globalThis.__DEV__
to determine if it should run in production or development mode.
Unlike Apollo Client 3 though, if globalThis.__DEV__ is not set to true,
Apollo Client will now default to production, not to development, behaviour.
This switch to explicilty requiring true also resolves a situation where
an HTML element with id="__DEV__" would create a global __DEV__ variable
with a referent to the DOM element, which in the past was picked up as "truthy" and
would have triggered development mode.
#12644 fe2f005 Thanks @jerelmiller! - Change the default Accept header to application/graphql-response+json,application/json;q=0.9.
#12476 6afff60 Thanks @jerelmiller! - Unify error behavior on subscriptions for GraphQL errors and network errors by ensuring network errors are subject to the errorPolicy. Network errors that terminate the connection will now be emitted on the error property passed to the next callback followed by a call to the complete callback.
#12499 ce35ea2 Thanks @phryneas! - Enable React compiler for hooks in ESM builds.
#12367 e6af35e Thanks @jerelmiller! - The reobserve option is no longer available in the result returned from useLazyQuery. This was considered an internal API and should not be used directly.
#12333 3e4beaa Thanks @jerelmiller! - Fix type of data property on ApolloQueryResult. Previously this field was non-optional, non-null TData, however at runtime this value could be set to undefined. This field is now reported as TData | undefined.
This will affect you in a handful of places:
data property emitted from the result passed to the next callback from client.watchQueryApolloQueryResult type such as observableQuery.refetch, observableQuery.fetchMore, etc.#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.
#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.
#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 },
+ }
+ ]);
#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
}
}
#12367 e6af35e Thanks @jerelmiller! - The promise returned when calling the execute function from useLazyQuery will now reject when using an errorPolicy of none when GraphQL errors are returned from the result.
#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.
#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
}
}
});
#12823 19e315e Thanks @jerelmiller! - Move all 1st party link types into a namespace.
#12223 69c1cb6 Thanks @jerelmiller! - Remove subscribeAndCount testing utility from @apollo/client/testing.
#12300 4d581e4 Thanks @jerelmiller! - Moves all React-related exports to the @apollo/client/react entrypoint and out of the main @apollo/client entrypoint. This prevents the need to install React in order to use the core client.
The following is a list of exports available in @apollo/client that should now import from @apollo/client/react.
ApolloConsumerApolloProvidercreateQueryPreloadergetApolloContextskipTokenuseApolloClientuseBackgroundQueryuseFragmentuseLazyQueryuseLoadableQueryuseMutationuseQueryuseQueryRefHandlersuseReactiveVaruseReadQueryuseSubscriptionuseSuspenseQueryThe following is a list of exports available in @apollo/client/testing that should now import from @apollo/client/testing/react:
MockedProvider#12525 8785186 Thanks @jerelmiller! - Throw an error when a client-only query is used in a mocked response passed to MockLink.
#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.
#12647 [a70fac6](https://github.com/apollographql/apollo-client/commit/a70fac6
Note truncated.
### Major Changes - #12850 `268cd80` Thanks @phryneas! - Introduce a versioning policy.
### Minor Changes - #12838 `b005561` Thanks @phryneas! - Add an entrypoint at @apollo/client/v4-migration that includes removed values and types. Each
```ts title="apollo-client.d.ts import { Defer20220824Handler } from "@apollo/client/incremental";
#12840 83e132a Thanks @phryneas! - If you use an incremental delivery handler, you now have to explicitly opt into adding the chunk types to the ApolloLink.Result type.
import { Defer20220824Handler } from "@apollo/client/incremental";
declare module "@apollo/client" {
export interface TypeOverrides extends Defer20220824Handler.TypeOverrides {}
}
#12841 65b503f Thanks @jerelmiller! - Remove the DataMasking interface exported from @apollo/client and @apollo/client/masking.
If you're using GraphQL Codegen to generate masked types, opt into the GraphQL Codegen masked types using declaration merging on the TypeOverides inte
#12837 7c49fdc Thanks @jerelmiller! - You must now opt in to use GraphQL Codegen data masking types when using Apollo Client's data masking feature. By default, Apollo Client now uses an identity type to apply to masked/unmasked types.
If you're using GraphQL Codegen to generate masked types, opt into the GraphQL Codegen masked types using declaration merging on the TypeOverides interface.
import { GraphQLCodegenDataMasking } from "@apollo/client/masking";
declare module "@apollo/client" {
export interface TypeOverrides
extends GraphQLCodegenDataMasking.TypeOverrides {}
}
#12837 7c49fdc Thanks @jerelmiller! - The types mode for data masking has been removed. Adding a types mode to the DataMasking interface has no effect. Remove the mode key in the module where you declare the DataMasking type for the @apollo/client module.
As a result, the Masked and MaskedDocumentNode types have also been removed since these have no effect when types are preserved.
### Minor Changes - #12828 `81b03d8` Thanks @phryneas! - invariant.error will now also log in production builds, not only dev builds ### Patch Changes
### Major Changes - #12825 `292b949` Thanks @jerelmiller! - The serializeFetchParameter helper is no longer exported and JSON.stringify is used direct
#12825 292b949 Thanks @jerelmiller! - The serializeFetchParameter helper is no longer exported and JSON.stringify is used directly. As such, the ClientParseError type has also been removed in favor of throwing any JSON serialize errors directly.
#12824 0506f12 Thanks @jerelmiller! - Ensure the error argument for the delay and attempts functions on RetryLink are an ErrorLike.
#12823 19e315e Thanks @jerelmiller! - Move all 1st party link types into a namespace.
#12823 19e315e Thanks @jerelmiller! - The OperationBatcher class is no longer exported from @apollo/client/link/batch. It is an implementation detail of BatchLink and should not be relied on directly.
#12824 0506f12 Thanks @jerelmiller! - RetryLink now emits a next event instead of an error event when encountering a protocol errors for multipart subscriptions when the operation is not retried. This ensures the observable notification remains the same as when RetryLink is not used.
#12819 7ff548d Thanks @jerelmiller! - update type of HttpLink.Options.fetchOptions to RequestInit
#12820 fba3d9e Thanks @jerelmiller! - The fetchOptions option provided to HttpLink and BatchHttpLink is now RequestInit instead of any. The credentials option is now a RequestCredentials type instead of a string.
#12823 19e315e Thanks @jerelmiller! - Fix the type of the argument for the sha256 function for PersistedQueryLink from ...any[] to string.
#12821 223a409 Thanks @jerelmiller! - Add a deprecation warning to WebSocketLink.
```diff const link = new ApolloLink(/* ... */);
#12809 e2a0be8 Thanks @jerelmiller! - operation.getContext now returns a Readonly<OperationContext> type.
#12809 e2a0be8 Thanks @jerelmiller! - The ApolloLink.Request (i.e. GraphQLRequest) passed to ApolloLink.execute no longer accepts operationName and operationType options. These properties are derived from the query and set on the returned ApolloLink.Operation type.
#12808 8e31a23 Thanks @phryneas! - HTTP Multipart handling will now throw an error if the connection closed before the final boundary has been received.
Data after the final boundary will be ignored.
#12809 e2a0be8 Thanks @jerelmiller! - operation.operationType is now a non-null OperationTypeNode. It is now safe to compare this value without having to check for undefined.
#12809 e2a0be8 Thanks @jerelmiller! - operation.operationName is now set as string | undefined where undefined represents an anonymous query. Previously operationName would return an empty string as the operationName for anonymous queries.
#12809 e2a0be8 Thanks @jerelmiller! - The concat, from, and split functions on ApollLink no longer support a plain request handler function. Please wrap the request handler with new ApolloLink.
const link = new ApolloLink(/* ... */);
link.concat(
- (operation, forward) => forward(operation),
+ new ApolloLink((operation, forward) => forward(operation)),
);
#12809 e2a0be8 Thanks @jerelmiller! - transformOperation and validateOperation have been removed and are no longer exported from @apollo/client/link/utils. These utilities have been merged into the implementation of createOperation. As a result, createOperation now returns a well-formed Operation object. Previously createOperation relied on an external call to transformOperation to provide a well-formed Operation type. If you use createOperation directly, remove the calls to transformOperation and validateOperation and pass the request directly.
#12809 e2a0be8 Thanks @jerelmiller! - The request handler provided to ApolloLink must now return an Observable. null is no longer supported as a valid return value. If you rely on null so that ApolloLink provides an empty observable, use the EMPTY observable from RxJS instead:
import { ApolloLink } from "@apollo/client";
+ import { EMPTY } from "rxjs";
const link = new ApolloLink((operation, forward) => {
- return null;
+ return EMPTY;
});
If you have a custom link that overrides the request method, remove null from the return signature:
class MyCustomLink extends ApolloLink {
request(
operation: ApolloLink.Operation,
forward: ApolloLink.ForwardFunction,
- ): Observable<ApolloLink.Result> | null {
+ ): Observable<ApolloLink.Result> {
// implementation
}
}
#12809 e2a0be8 Thanks @jerelmiller! - createOperation no longer accepts context as the first argument. Instead make sure context is set as the context property on the request passed to createOperation.
createOperation(
- startingContext,
- { query },
+ { query, context: startingContext },
{ client }
);
#12809 e2a0be8 Thanks @jerelmiller! - Remove the TVariables generic argument on the GraphQLRequest type.
#12809 e2a0be8 Thanks @jerelmiller! - The context object returned from operation.getContext() is now frozen to prevent mutable changes to the object which could result in subtle bugs. This applies to the previousContext object passed to the operation.setContext() callback as well.
#12809 e2a0be8 Thanks @jerelmiller! - The forward function passed to the request handler is now always provided to request and no longer optional. If you create custom links by subclassing ApolloLink, the forward function no longer needs to be optional:
class CustomLink extends ApolloLink {
request(
operation: ApolloLink.Operation,
// This no longer needs to be typed as optional
forward: ApolloLink.ForwardFunction
) {
// ...
}
}
As a result of this change, ApolloLink no longer detects terminating links by checking function arity on the request handler. This means using methods such as concat on a terminating link no longer emit a warning. On the flip side, if the terminating link calls the forward function, a warning is emitted and an observable that immediately completes is returned which will result in an error from Apollo Client.
#12809 e2a0be8 Thanks @jerelmiller! - ApolloLink's concat method now accepts multiple links to concatenate together.
const first = new ApolloLink();
const link = first.concat(second, third, fouth);
#12809 e2a0be8 Thanks @jerelmiller! - Many of the types exported from @apollo/client/link now live on the ApolloLink namespace. The old types are now deprecated in favor of the namespaced types.
FetchResult -> ApolloLink.ResultGraphQLRequest -> ApolloLink.RequestNextLink -> ApolloLink.ForwardFunctionOperation -> ApolloLink.OperationRequestHandler -> ApolloLink.RequestHandler#12809 e2a0be8 Thanks @jerelmiller! - The static ApolloLink.concat method is now deprecated in favor of ApolloLink.from. ApolloLink.concat is now an alias for ApolloLink.from so prefer ApolloLink.from instead.
#12809 e2a0be8 Thanks @jerelmiller! - The individual empty, concat, from and split functions exported from @apollo/client/link are now deprecated in favor of using the static functions instead.
import {
ApolloLink,
- concat,
- empty,
- from,
- split,
} from "@apollo/client/link";
- concat(first, second);
+ ApolloLink.concat(first, second);
- empty();
+ ApolloLink.empty();
- from([first, second]);
+ ApolloLink.from([first, second]);
- split(
+ ApolloLink.split(
(operation) => /* */,
first,
second
);
### Major Changes - #12787 `8ce31fa` Thanks @phryneas! - Remove DataProxy namespace and interface. - #12788 `4179446` Thanks @phryneas! - TVariables n
#12787 8ce31fa Thanks @phryneas! - Remove DataProxy namespace and interface.
#12788 4179446 Thanks @phryneas! - TVariables now always extends OperationVariables in all interfaces.
#12802 e2b51b3 Thanks @jerelmiller! - Disallow the mutation option for the mutate function returned from useMutation.
#12787 8ce31fa Thanks @phryneas! - Generic arguments for Cache.ReadOptions were flipped from TVariables, TData to TData, TVariables.
#12793 24e98a1 Thanks @phryneas! - ApolloConsumer has been removed - please use useApolloClient instead.
742b3a0 Thanks @jerelmiller! - Move ApolloClient, ObservableQuery, and ApolloCache.watchFragment method options and result types into namespaces. The old types are now exported as deprecated.NOTE: This change does not affect the equivalent cache.* APIs. To read data from the cache without first running document transforms, run cache.readQu
#12776 bce9b74 Thanks @jerelmiller! - Report masked fragments as complete even when a nested masked fragment contains partial data.
#12774 511b4f3 Thanks @jerelmiller! - Apply document transforms before reading data from the cache for client.readQuery, client.readFragment, client.watchFragment, useFragment, and useSuspenseFragment.
NOTE: This change does not affect the equivalent cache.* APIs. To read data from the cache without first running document transforms, run cache.readQuery, cache.readFragment, etc.
bce9b74 Thanks @jerelmiller! - Add dataState to the value emitted from client.watchFragment.#12776 bce9b74 Thanks @jerelmiller! - cache.watchFragment now returns an Unmasked<TData> result since cache.watchFragment does not mask fragment spreads.
#12370 0517163 Thanks @phryneas! - InMemoryCache: Fields with an empty argument object are now saved the same way as fields without arguments.
Previously, it was possible that the reponses for these two queries would be stored differently in the cache:
query PlainAccess {
myField
}
would be stored as myField
and
query AccessWithoutOptionalArgument($optional: String) {
myField(optional: $optional)
}
would be stored as myField({"optional":"Foo"}) if called with {optional: "Foo"} and as myField({}) if called without the optional argument.
The cases myField and myField({}) are equivalent from the perspective of a GraphQL server, and so in the future both of these will be stored as myField in the cache.
#12775 454ec78 Thanks @jerelmiller! - Don't export gql from @apollo/client/react entrypoint. Import from @apollo/client instead.
#12761 db6f7c3 Thanks @phryneas! - Deprecate second argument to readFragment and readQuery - optimistic should be passed as part of the object in the first argument instead.
### Minor Changes - #12757 `5fd2e7c` Thanks @phryneas! - Add dataState and overridable DataValue types to useFragment - #12757 `5fd2e7c` Thanks @phryn
We now ship a React-Compiler compiled version of the React hooks in @apollo/client/react/compiled.
#12731 0198870 Thanks @phryneas! - Ship React Compiler compiled React hooks in @apollo/client/react/compiled.
We now ship a React-Compiler compiled version of the React hooks in
@apollo/client/react/compiled.
This entry point contains everything that @apollo/client/react does,
so you can use it as a drop-in replacement in your whole application
if you choose to use the compiled hooks.
b85818d Thanks @jerelmiller! - Renamed client.reFetchObservableQueries to client.refetchObservableQueries.
client.reFetchObservableQueries is still available as an alias, but is now
deprecated and will be removed in a future major version.new SetContextLink((operation, prevContext) => {
#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;
}
}
import { getMainDefinition } from "@apollo/client/utilities";
#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.
### Major Changes - #12718 `ecfc02a` Thanks @jerelmiller! - Version bump only to release latest as rc.
ecfc02a Thanks @jerelmiller! - Version bump only to release latest as rc.This means useQuery will no longer render a short initial loading state before rendering loading: false and ObservableQuery.getCurrentResult() will no
#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.
If includeExtensions is true, but extensions is not set or empty, extensions will not be included in outgoing requests.
#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.
### Major Changes - #12686 `dc4b1d0` Thanks @jerelmiller! - A @defer query that has not yet finished streaming is now considered loading and thus the
#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.
That means that ApolloClient.getObservableQueries and ApolloClient.refetchQueries will only be able to return/refetch queries that have at least one s
#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".```ts const observable = client.subscribe({ query: subscription });
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.
Up until now, our types Masked, MaskedDocumentNode, FragmentType, MaybeMasked and Unmasked would assume that you are stictly using the type output for
#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.
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):
#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>();
}
The client will parse the response as a well-formed GraphQL response when the server encodes content-type using application/graphql-response+json with
#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.
The following APIs were removed. To migrate, update usages of the following APIs as such:
#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 = {}
`ts class MyCache extends ApolloCache { // This is now required public fragmentMatches( fragment: InlineFragmentNode | FragmentDefinitionNode, typenam
#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>({
// ...
});
…and considered stable and will not undergo breaking changes.
#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.If using `uri`, `credentials`, or `headers` options
#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()
});
```ts ApolloLink.execute(link, operation, { client });
#12576 a92ff78 Thanks @jerelmiller! - The cache and forceFetch properties are no longer available on context when calling operation.getContext(). cache can be accessed through the operation with operation.client.cache instead. forceFetch has been replaced with queryDeduplication which specifies whether queryDeduplication was enabled for the request or not.
#12576 a92ff78 Thanks @jerelmiller! - ApolloLink.execute now requires a third argument which provides the client that initiated the request to the link chain. If you use execute directly, add a third argument with a client property:
ApolloLink.execute(link, operation, { client });
// or if you import the `execute` function directly:
execute(link, operation, { client });
#12566 ce4b488 Thanks @jerelmiller! - Don't broadcastQueries when a query is torn down.
#12576 a92ff78 Thanks @jerelmiller! - Provide an extension to define types for context passed to the link chain. To define your own types, use declaration merging to add properties to the DefaultContext type.
// @apollo-client.d.ts
// This import is necessary to ensure all Apollo Client imports
// are still available to the rest of the application.
import "@apollo/client";
declare module "@apollo/client" {
interface DefaultContext extends Record<string, any> {
myProperty: string;
}
}
Links that provide context options can be used with this type to add those context types to DefaultContext. For example, to add context options from HttpLink, add the following code:
import { HttpLink } from "@apollo/client";
declare module "@apollo/client" {
interface DefaultContext extends HttpLink.ContextOptions {
myProperty: string;
}
}
At this time, the following built-in links support context options:
HttpLink.ContextOptionsBatchHttpLink.ContextOptions#12576 a92ff78 Thanks @jerelmiller! - Add a client property to the operation passed to the link chain. This client is set as the client making the request to the link chain.
#12574 0098ec9 Thanks @jerelmiller! - Export gql from the @apollo/client/react entrypoint.
#12572 3dc50e6 Thanks @jerelmiller! - Adjust useMutation types to better handle required variables. When required variables are missing, TypeScript will now complain if they are not provided either to the hook or the returned mutate function. Providing required variables to useMutation will make them optional in the returned mutate function.
``ts // given this query const query = gql query PaginatedQuery($limit: Int! = 10, $offset: Int) { list(limit: $limit, offset: $offset) { id } } `;
#12559 49ace0e Thanks @jerelmiller! - ObservableQuery.variables can now be reset back to empty when calling reobserve with variables: undefined. Previously the variables key would be ignored so variables would remain unchanged.
#12559 49ace0e Thanks @jerelmiller! - never is no longer supported as a valid TVariables generic argument for APIs that require variables as part of its type. Use Record<string, never> instead.
#12559 49ace0e Thanks @jerelmiller! - When passing a variables key with the value undefined, the value will be replaced by the default value in the query, if it is provided, rather than leave it as undefined.
// given this query
const query = gql`
query PaginatedQuery($limit: Int! = 10, $offset: Int) {
list(limit: $limit, offset: $offset) {
id
}
}
`;
const observable = client.query({
query,
variables: { limit: 5, offset: 0 },
});
console.log(observable.variables); // => { limit: 5, offset: 0 }
observable.reobserve({ variables: { limit: undefined, offset: 10 } });
// limit is now `10`. This would previously be `undefined`
console.log(observable.variables); // => { limit: 10, offset: 10 }
#12562 90bf0e6 Thanks @jerelmiller! - client.query no longer supports a fetchPolicy of standby. standby does not fetch and did not return data. standby is meant for watched queries where fetching should be on hold.
#12557 51d26ae Thanks @jerelmiller! - Add ability to specify message formatter for CombinedGraphQLErrors and CombinedProtocolErrors. To provide your own message formatter, override the static formatMessage property on these classes.
CombinedGraphQLErrors.formatMessage = (
errors,
{ result, defaultFormatMessage }
) => {
return "Some formatted message";
};
CombinedProtocolErrors.formatMessage = (errors, { defaultFormatMessage }) => {
return "Some formatted message";
};
#12546 5dffbbe Thanks @jerelmiller! - Add a static is method to error types defined by Apollo Client. is makes it simpler to determine whether an error is a specific type, which can be helpful in cases where you'd like to narrow the error type in order to use specific properties from that error.
This change applies to the following error types:
CombinedGraphQLErrorsCombinedProtocolErrorsServerErrorServerParseErrorUnconventionalErrorExample
import { CombinedGraphQLErrors } from "@apollo/client";
if (CombinedGraphQLErrors.is(error)) {
console.log(error.message);
error.errors.forEach((graphQLError) => console.log(graphQLError.message));
}
#12561 99d72bf Thanks @jerelmiller! - Add the ability to detect if an error was an error was emitted from the link chain. This is useful if your application throws custom errors in other areas of the application and you'd like to differentiate them from errors emitted by the link chain itself.
To detect if an error was emitted from the link chain, use LinkError.is.
import { LinkError } from "@apollo/client";
client.query({ query }).catch((error) => {
if (LinkError.is(error)) {
// This error originated from the link chain
}
});
#12559 49ace0e Thanks @jerelmiller! - The variables option used with various APIs are now enforced more consistently across the client when TVariables contains required variables. If required variables are not provided, TypeScript will now complain that it requires a variables option.
This change affects the following APIs:
client.queryclient.mutateclient.subscribeclient.watchQueryuseBackgroundQueryuseQueryuseSubscriptionuseSuspenseQuery#12559 49ace0e Thanks @jerelmiller! - Fix type of variables returned from useLazyQuery. When called is false, variables is now Partial<TVariables> instead of TVariables.
#12562 90bf0e6 Thanks @jerelmiller! - client.query no longer supports notifyOnNetworkStatusChange in options. An error will be thrown if this option is set. The effects of this option were not observable by client.query since client.query emits a single result.
#12557 51d26ae Thanks @jerelmiller! - Update format of the error message for CombinedGraphQLErrors and CombinedProtocolErrors to be more like v3.x.
console.log(error.message);
- `The GraphQL server returned with errors:
- - Email not found
- - Username already in use`
+ `Email not found
+ Username already in use`
#12559 49ace0e Thanks @jerelmiller! - ObservableQuery.variables has been updated to return TVariables rather than TVariables | undefined. This is more consistent with the runtime value where an empty object ({}) will be returned when the variables option is not provided.
`ts new ApolloClient({ defaultOptions: { watchQuery: { // Use the v3 default notifyOnNetworkStatusChange: false, }, }, }); `
#12536 e14205a Thanks @jerelmiller! - An initial loading state is now emitted from ObservableQuery when subscribing if notifyOnNetworkStatusChange is set to true.
#12512 e809b71 Thanks @jerelmiller! - notifyOnNetworkStatusChange now defaults to true. This means that loading states will be emitted (core API) or rendered (React) by default when calling refetch, fetchMore, etc. To maintain the old behavior, set notifyOnNetworkStatusChange to false in defaultOptions.
new ApolloClient({
defaultOptions: {
watchQuery: {
// Use the v3 default
notifyOnNetworkStatusChange: false,
},
},
});
#12536 e14205a Thanks @jerelmiller! - The returned networkStatus in useLazyQuery is now set to setVariables when calling the useLazyQuery execute function for the first time with variables.
#12536 e14205a Thanks @jerelmiller! - Ensure ObservableQuery stops polling if switching to a standby fetchPolicy. When switching back to a non-standby fetchPolicy, polling will resume.
#12536 e14205a Thanks @jerelmiller! - Ensure a loading state is emitted when calling the execute function after changing clients in useLazyQuery.
#12542 afb4fce Thanks @jerelmiller! - Ensure useLazyQuery does not return a partial property which is not specified by the result type.
const errorLink = onError(({ graphQLErrors, networkError, protocolErrors }) => {
#12539 dd0d6d6 Thanks @jerelmiller! - onError link now uses a single error property to report the error that caused the link callback to be called. This will be an instance of CombinedGraphQLErrors in the event GraphQL errors were emitted from the terminating link, CombinedProtocolErrors if the terminating link emitted protocol errors, or the unwrapped error type if any other non-GraphQL error was thrown or emitted.
- const errorLink = onError(({ graphQLErrors, networkError, protocolErrors }) => {
- graphQLErrors.forEach(error => console.log(error.message));
+ const errorLink = onError(({ error }) => {
+ if (error.name === 'CombinedGraphQLErrors') {
+ error.errors.forEach(rawError => console.log(rawError.message));
+ }
});
#12533 73221d8 Thanks @jerelmiller! - Remove the onError and setOnError methods from ApolloLink. onError was only used by MockLink to rewrite errors if setOnError was used.
#12531 7784b46 Thanks @jerelmiller! - Mocked responses passed to MockLink now accept a callback for the request.variables option. This is used to determine if the mock should be matched for a set of request variables. With this change, the variableMatcher option has been removed in favor of passing a callback to variables. Update by moving the callback function from variableMatcher to request.variables.
new MockLink([
{
request: {
query,
+ variables: (requestVariables) => true
},
- variableMatcher: (requestVariables) => true
}
]);
#12526 391af1d Thanks @phryneas! - The @apollo/client and @apollo/client/core entry points are now equal.
In the next major, the @apollo/client/core entry point will be removed.
Please change imports over from @apollo/client/core to @apollo/client.
#12525 8785186 Thanks @jerelmiller! - Throw an error when a client-only query is used in a mocked response passed to MockLink.
#12532 ae0dcad Thanks @jerelmiller! - Default the delay for all mocked responses passed to MockLink using realisticDelay. This ensures your test handles loading states by default and is not reliant on a specific timing.
If you would like to restore the old behavior, use a global default delay of 0.
MockLink.defaultOptions = {
delay: 0,
};
#12530 2973e2a Thanks @jerelmiller! - Remove newData option for mocked responses passed to MockLink or the mocks option on MockedProvider. This option was undocumented and was nearly identical to using the result option as a callback.
To replicate the old behavior of newData, use result as a callback and add the maxUsageCount option with a value set to Number.POSITIVE_INFINITY.
with MockLink
new MockLink([
{
request: { query, variables },
- newData: (variables) => ({ data: { greeting: "Hello " + variables.greeting } }),
+ result: (variables) => ({ data: { greeting: "Hello " + variables.greeting } }),
+ maxUsageCount: Number.POSITIVE_INFINITY,
}
])
with MockedProvider
<MockedProvider
mocks={[
{
request: { query, variables },
- newData: (variables) => ({ data: { greeting: "Hello " + variables.greeting } }),
+ result: (variables) => ({ data: { greeting: "Hello " + variables.greeting } }),
+ maxUsageCount: Number.POSITIVE_INFINITY,
}
]}
/>
#12532 ae0dcad Thanks @jerelmiller! - Allow mocked responses passed to MockLink to accept a callback for the delay option. The delay callback will be given the current operation which can be used to determine what delay should be used for the mock.
#12532 ae0dcad Thanks @jerelmiller! - Introduce a new realisticDelay helper function for use with the delay callback for mocked responses used with MockLink. realisticDelay will generate a random value between 20 and 50ms to provide an experience closer to unpredictable network latency. realisticDelay can be configured with a min and max to set different thresholds if the defaults are not sufficient.
import { realisticDelay } from "@apollo/client/testing";
new MockLink([
{
request: { query },
result: { data: { greeting: "Hello" } },
delay: realisticDelay(),
},
{
request: { query },
result: { data: { greeting: "Hello" } },
delay: realisticDelay({ min: 10, max: 100 }),
},
]);
#12532 ae0dcad Thanks @jerelmiller! - Add ability to specify a default delay for all mocked responses passed to MockLink. This delay can be configured globally (all instances of MockLink will use the global defaults), or per-instance (all mocks in a single instance will use the defaults). A delay defined on a single mock will supercede all default delays. Per-instance defaults supercede global defaults.
Global defaults
MockLink.defaultOptions = {
// Use a default delay of 20ms for all mocks in all instances without a specified delay
delay: 20,
// altenatively use a callback which will be executed for each mock
delay: () => getRandomNumber(),
// or use the built-in `realisticDelay`. This is the default
delay: realisticDelay(),
};
Per-instance defaults
new MockLink(
[
// Use the default delay
{
request: { query },
result: { data: { greeting: "Hello" } },
},
{
request: { query },
result: { data: { greeting: "Hello" } },
// Override the default for this mock
delay: 10,
},
],
{
defaultOptions: {
// Use a default delay of 20ms for all mocks without a specified delay
delay: 20,
// altenatively use a callback which will be executed for each mock
delay: () => getRandomNumber(),
// or use the built-in `realisticDelay`. This is the default
delay: realisticDelay(),
},
}
);
### Major Changes - #12513 `9c3207c` Thanks @phryneas! - Removed the @apollo/client/react/context and @apollo/client/react/hooks entry points. Please
#12513 9c3207c Thanks @phryneas! - Removed the @apollo/client/react/context and @apollo/client/react/hooks entry points. Please use @apollo/client/react instead.
#12513 9c3207c Thanks @phryneas! - Removed the @apollo/client/react/parser entry point. There is no replacement.
This affects the following APIs:
#12485 d338303 Thanks @jerelmiller! - Throw an error for queries and mutations if the link chain completes without emitting a value.
#12484 9a8b9ce Thanks @jerelmiller! - Remove loading, networkStatus, and partial properties on all promise-based query APIs. These properties were mostly static and were unnecessary since promise resolution guaranteed that the query was not longer loading.
This affects the following APIs:
client.queryclient.refetchQueriesclient.reFetchObservableQueriesclient.resetStoreobservableQuery.fetchMoreobservableQuery.refetchobservableQuery.reobserveobservableQuery.setVariablesuseLazyQuery execute function#12497 ff2cbe1 Thanks @jerelmiller! - Add a data property to CombinedGraphQLErrors that captures any partial data returned by the GraphQL response when errors are also returned.
#12488 c98b633 Thanks @phryneas! - Add a new method for static SSR of React components, prerenderStatic.
The old methods, getDataFromTree, getMarkupFromTree and renderToStringWithData
have been deprecated in favor of prerenderStatic.
If used with React 19 and the prerender or prerenderToNodeStream apis from
react-dom/static, this method can now be used to SSR-prerender suspense-enabled
hook APIs.
useMutation now also returns a MutateResult instead of a FetchResult.
#12478 5ea6a45 Thanks @jerelmiller! - Remove variables from the result returned from useSubscription.
#12476 6afff60 Thanks @jerelmiller! - Subscriptions now emit a SubscribeResult instead of a FetchResult. As a result, the errors field has been removed in favor of error.
#12475 3de63eb Thanks @jerelmiller! - Unify error behavior on mutations for GraphQL errors and network errors by ensuring network errors are subject to the errorPolicy. Network errors created when using an errorPolicy of all will now resolve the promise and be returned on the error property of the result, or stripped away when the errorPolicy is none.
#12475 3de63eb Thanks @jerelmiller! - client.mutate now returns a MutateResult instead of FetchResult. As a result, the errors property has been removed in favor of error which is set if either a network error occured or GraphQL errors are returned from the server.
useMutation now also returns a MutateResult instead of a FetchResult.
#12475 3de63eb Thanks @jerelmiller! - Mutations no longer report errors if the GraphQL result from the server contains an empty array of errors.
#12476 6afff60 Thanks @jerelmiller! - Unify error behavior on subscriptions for GraphQL errors and network errors by ensuring network errors are subject to the errorPolicy. Network errors that terminate the connection will now be emitted on the error property passed to the next callback followed by a call to the complete callback.
#12478 5ea6a45 Thanks @jerelmiller! - Remove deprecated onSubscriptionData and onSubscriptionComplete callbacks from useSubscription. Use onData and onComplete instead.
#12476 6afff60 Thanks @jerelmiller! - GraphQL errors or network errors emitted while using an errorPolicy of ignore in subscriptions will no longer emit a result if there is no data emitted along with the error.
#12476 6afff60 Thanks @jerelmiller! - Subscriptions no longer emit errors in the error callback and instead provide errors on the error property on the result passed to the next callback. As a result, errors will no longer automatically terminate the connection allowing additional results to be emitted when the connection stays open.
When an error terminates the downstream connection, a next event will be emitted with an error property followed by a complete event instead.
b695e5e Thanks @phryneas! - Split out SSR-specific code from useQuery hook, remove RenderPromises#12487 b695e5e Thanks @phryneas! - useQuery with ssr: false - previously, skip had a higher priortity than ssr: false while ssr: false had a higher priority than fetchPolicy: "standby" (which is roughly equivalent to skip).
This priority has been adjusted so now both skip and fetchPolicy: "standby" have a higher priority than ssr: false and will return loading: false, while ssr: false will only come after those and will return loading: true if those are not set.
#12475 3de63eb Thanks @jerelmiller! - Fix an issue where passing onError to useMutation would resolve the promise returned by the mutate function instead of rejecting when using an errorPolicy of none.
#12475 3de63eb Thanks @jerelmiller! - Fix an issue where additional response properties were returned on the result returned from client.mutate, such as @defer payload fields. These properties are now stripped out to correspond to the TypeScript type.
```diff const observable = client.watchQuery(options);
#12463 3868df8 Thanks @jerelmiller! - ObservableQuery.setOptions has been removed as it was an alias of reobserve. Prefer using reobserve directly instead.
const observable = client.watchQuery(options);
// Use reobserve to set new options and reevaluate the query
- observable.setOptions(newOptions);
+ observable.reobserve(newOptions);
As a result of this change, reobserve has been marked for public use and is no longer considered an internal API. The newNetworkStatus argument has been removed to facilitate this change.
#12470 d32902f Thanks @phryneas! - ssrMode, ssrForceFetchDelay and disableNetworkFetches have been reworked:
Previously, a ObservableQuery created by client.query or client.watchQuery
while one of those were active would permanently be changed from a fetchPolicy
of "network-only" or "cache-and-network" to "cache-first", and stay that way
even long after disableNetworkFetches would have been deactivated.
Now, the ObservableQuery will keep their original fetchPolicy, but queries
made during disableNetworkFetches will just apply the fetchPolicy replacement
at request time, just for that one request.
ApolloClient.disableNetworkFetches has been renamed to ApolloClient.prioritizeCacheValues to better reflect this behaviour.
#12465 a132163 Thanks @jerelmiller! - Flatten out React hook types. As a result, the base types have been removed. Prefer using the hook types instead. Removed types include:
BaseMutationOptionsBaseQueryOptionsBaseSubscriptionOptionsObservableQueryFieldsMutationSharedOptionsQueryFunctionOptions#12463 3868df8 Thanks @jerelmiller! - useQuery no longer returns reobserve as part of its result. It was possible to use reobserve to set new options on the underlying ObservableQuery instance which differed from the options passed to the hook. This could result in unexpected results. Instead prefer to rerender the hook with new options.
a132163 Thanks @jerelmiller! - Rename all React hook result types and options. These types have all moved under a namespace that matches the hook name. For example, useQuery exports useQuery.Options and useQuery.Result types. As such, the old hook types have been deprecated and will be removed in v5.### Major Changes - #12457 `32e85ea` Thanks @jerelmiller! - Network errors triggered by queries now adhere to the errorPolicy. This means that GraphQL
#12457 32e85ea Thanks @jerelmiller! - Network errors triggered by queries now adhere to the errorPolicy. This means that GraphQL errors and network errors now behave the same way. Previously promise-based APIs, such as client.query, would reject the promise with the network error even if errorPolicy was set to ignore. The promise is now resolved with the error property set to the network error instead.
#12464 0595f39 Thanks @jerelmiller! - Remove the called property from useQuery.
### Major Changes - #12450 `876d070` Thanks @jerelmiller! - Remove TSerialized generic argument to ApolloCache. The ApolloCache base cache abstraction
#12450 876d070 Thanks @jerelmiller! - Remove TSerialized generic argument to ApolloCache. The ApolloCache base cache abstraction now returns unknown for cache.extract which can be overridden by a cache subclass.
#12450 876d070 Thanks @jerelmiller! - Remove the TCacheShape generic argument to ApolloClient. client.extract() now returns unknown by default. You will either need to type-cast this to the expected serialized shape, or use the cache.extract() directly from the subclass to get more specific types.
#12446 ab920d2 Thanks @jerelmiller! - Removes the defaultOptions option from useQuery. Use options directly or use the global ApolloClient defaultOptions.
#12442 c5ead08 Thanks @jerelmiller! - Remove the deprecated canonizeResults option. It was prone to memory leaks. As such, some results that were referentially equal when canonizeResults option was set to true no longer retain the same object identity.
#12442 c5ead08 Thanks @jerelmiller! - Remove resetResultIdentities option from InMemoryCache.gc(). This affected object canonization which has been removed.
#12451 77e1b13 Thanks @jerelmiller! - Default the TData generic type to unknown in all APIs that use a TData generic argument such as useQuery, client.query, etc.
This removes support for fetch implementations that return Node Streams, Async Iterators or Blob instances as Response.body.
#12433 b86e50b Thanks @phryneas! - Remove workarounds for streaming with non-WhatWG response bodies to reduce bundle size.
This removes support for fetch implementations that return Node Streams, Async Iterators or Blob instances as Response.body.
In the WhatWG Fetch specification, Response.body is specified as a WhatWG ReadableStream.
At this point in time, this is natively supported in browsers, node and React Native (via react-native-fetch-api, see our setup instructions for React Native).
If you are using an older fetch polyfill that deviates from the spec, this might not be compatible - for example, node-fetch returns a node Readable instead of a ReadableStream.
In those cases, please switch to a compatible alternative such as the node-native fetch, or undici.
#12438 5089516 Thanks @phryneas! - Drop rehackt dependency.
We can now directly import from react without causing build errors in RSC.
#12437 4779dc7 Thanks @phryneas! - Remove polyfills for Object.freeze,seal and preventExtensions in React Native
These polyfills were only necessary until React Native 0.59, which patched the problem on the React Native side.
With React Native 0.61, the Map function was completely replaced
with a native implementation that never had the problems we guarded against.
#12438 5089516 Thanks @phryneas! - Add react-server entry point with stubs for normal exports.
Your coding agent can read these notes before it upgrades. Set up the MCP server →