Skip to content

feat(core-backend): expose query options#7928

Merged
Kriys94 merged 1 commit intomainfrom
feature/ImproveCoreBackend
Feb 13, 2026
Merged

feat(core-backend): expose query options#7928
Kriys94 merged 1 commit intomainfrom
feature/ImproveCoreBackend

Conversation

@Kriys94
Copy link
Contributor

@Kriys94 Kriys94 commented Feb 13, 2026

Improve @metamask/core-backend: ApiPlatformClientService + Query Options

Explanation

What is the current state of things and why does it need to change?

  • ApiPlatformClient is today passed by reference (e.g. into AssetsController and its data sources). Consumers that want to use the API client must receive it via constructor or similar injection. There was no way to obtain the client through the messenger only, which is useful when wiring services in a controller-based app without introducing a dedicated controller for the client.
  • TanStack Query options used internally by the API clients (e.g. for fetchV5MultiAccountBalances, fetchV3SpotPrices) were not exposed. Consumers that want to use useQuery, useInfiniteQuery, or useSuspenseQuery with the same query keys and options had to duplicate or reverse-engineer them.

What is the solution your changes offer and how does it work?

  1. ApiPlatformClientService
    A new service (not a controller) in @metamask/core-backend that holds an ApiPlatformClient and exposes it via the messenger, following the same pattern as SampleGasPricesService. The service is constructed with messenger plus ApiPlatformClientOptions (e.g. clientProduct, getBearerToken). It registers a single action, ApiPlatformClientService:getApiPlatformClient, which returns the shared client. Consumers can call messenger.call('ApiPlatformClientService:getApiPlatformClient') to get the client and then use client.accounts, client.prices, client.token, and client.tokens as usual.

  2. Exported query options
    For every fetch method on the Accounts, Prices, Token, and Tokens API clients, a corresponding get*QueryOptions helper is exported (e.g. getV5MultiAccountBalancesQueryOptions, getV3SpotPricesQueryOptions). Each returns the same TanStack Query options object (queryKey, queryFn, staleTime, gcTime, etc.) that the client uses internally. The existing fetch methods now call these helpers and pass the result to queryClient.fetchQuery, so behavior is unchanged. Consumers can call the same helpers and pass the result to useQuery, useInfiniteQuery, useSuspenseQuery, or any API that accepts TanStack Query options.

Are there any changes whose purpose might not be obvious to those unfamiliar with the domain?

  • Why a service instead of a controller?
    The goal is to expose a single capability (obtaining the API client) without persistent state or controller lifecycle. The Core data-service guidelines and the sample package use a service (plain class + registerMethodActionHandlers) for this; the same pattern is used by BackendWebSocketService and AccountActivityService in core-backend.

  • Why export query options instead of only fetch methods?
    UI that uses React Query (or similar) needs the options object (queryKey, queryFn, staleTime, etc.) to plug into useQuery / useInfiniteQuery / useSuspenseQuery. Exposing it keeps a single source of truth for keys and behavior and avoids drift between “fetch” and “hook” usage.

If your primary goal was to update one package but you found you had to update another one along the way, why did you do so?

All changes are confined to @metamask/core-backend. No other packages were modified.

If you had to upgrade a dependency, why did you do so?

No dependency upgrades in this PR.


References

  • Fixes: (add issue number if applicable)
  • Related: (e.g. consumer PRs that will use ApiPlatformClientService or get*QueryOptions)

Checklist

  • I've updated the test suite for new or updated code as appropriate
    • Added ApiPlatformClientService.test.ts; fixed lint in that file.
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
    • JSDoc added for all get*QueryOptions; service and README already document usage.
  • I've communicated my changes to consumers by updating changelogs for packages I've changed
    • packages/core-backend/CHANGELOG.md: entries for ApiPlatformClientService and for exported query options.
  • I've introduced breaking changes in this PR and have prepared draft pull requests for clients and consumer packages to resolve them
    • N/A. No breaking changes.

Note

Medium Risk
Medium risk due to multiple public API surface changes (renamed params, removed methods/options, and altered error semantics) that can break downstream callers and caching keys if not updated consistently.

Overview
Introduces ApiPlatformClientService, a new messenger-exposed service that provides a shared ApiPlatformClient instance via ApiPlatformClientService:getApiPlatformClient.

Across accounts, prices, token, and tokens clients, adds get*QueryOptions helpers for each endpoint and extends FetchOptions to accept TanStack Query options; getQueryOptionsOverrides is added/exported to merge caller overrides while preserving client-owned queryKey/queryFn and consistent staleTime/gcTime defaults.

Makes breaking API adjustments to align with backend specs: merges fetchV2BalancesWithOptions into fetchV2Balances, updates v4 multi-account transactions to use accountAddresses and expanded filter params (removing includeValueTransfers), and changes some edge behavior (short-circuit empty required inputs to return empty results; relationship and fetchV1TokenPrice error paths now throw instead of returning sentinel values).

Written by Cursor Bugbot for commit 45a8b60. This will update automatically on new commits. Configure here.

@Kriys94 Kriys94 force-pushed the feature/ImproveCoreBackend branch 3 times, most recently from 84c13aa to b1e1749 Compare February 13, 2026 10:16
@Kriys94 Kriys94 marked this pull request as ready for review February 13, 2026 10:17
@Kriys94 Kriys94 requested review from a team as code owners February 13, 2026 10:17
@Kriys94 Kriys94 force-pushed the feature/ImproveCoreBackend branch from b1e1749 to 1a23080 Compare February 13, 2026 10:51
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

@Kriys94 Kriys94 force-pushed the feature/ImproveCoreBackend branch 2 times, most recently from 2cff407 to cd9ed57 Compare February 13, 2026 15:43
@Kriys94 Kriys94 force-pushed the feature/ImproveCoreBackend branch from cd9ed57 to 45a8b60 Compare February 13, 2026 15:49
@Kriys94 Kriys94 added this pull request to the merge queue Feb 13, 2026
Merged via the queue into main with commit 2dd9208 Feb 13, 2026
302 checks passed
@Kriys94 Kriys94 deleted the feature/ImproveCoreBackend branch February 13, 2026 16:32
khanti42 pushed a commit that referenced this pull request Feb 20, 2026
# Improve @metamask/core-backend: ApiPlatformClientService + Query
Options

## Explanation

### What is the current state of things and why does it need to change?

- **ApiPlatformClient** is today passed by reference (e.g. into
`AssetsController` and its data sources). Consumers that want to use the
API client must receive it via constructor or similar injection. There
was no way to obtain the client through the messenger only, which is
useful when wiring services in a controller-based app without
introducing a dedicated controller for the client.
- **TanStack Query options** used internally by the API clients (e.g.
for `fetchV5MultiAccountBalances`, `fetchV3SpotPrices`) were not
exposed. Consumers that want to use `useQuery`, `useInfiniteQuery`, or
`useSuspenseQuery` with the same query keys and options had to duplicate
or reverse-engineer them.

### What is the solution your changes offer and how does it work?

1. **ApiPlatformClientService**  
A new **service** (not a controller) in `@metamask/core-backend` that
holds an `ApiPlatformClient` and exposes it via the messenger, following
the same pattern as `SampleGasPricesService`. The service is constructed
with `messenger` plus `ApiPlatformClientOptions` (e.g. `clientProduct`,
`getBearerToken`). It registers a single action,
`ApiPlatformClientService:getApiPlatformClient`, which returns the
shared client. Consumers can call
`messenger.call('ApiPlatformClientService:getApiPlatformClient')` to get
the client and then use `client.accounts`, `client.prices`,
`client.token`, and `client.tokens` as usual.

2. **Exported query options**  
For every fetch method on the Accounts, Prices, Token, and Tokens API
clients, a corresponding **`get*QueryOptions`** helper is exported (e.g.
`getV5MultiAccountBalancesQueryOptions`, `getV3SpotPricesQueryOptions`).
Each returns the same TanStack Query options object (queryKey, queryFn,
staleTime, gcTime, etc.) that the client uses internally. The existing
fetch methods now call these helpers and pass the result to
`queryClient.fetchQuery`, so behavior is unchanged. Consumers can call
the same helpers and pass the result to `useQuery`, `useInfiniteQuery`,
`useSuspenseQuery`, or any API that accepts TanStack Query options.

### Are there any changes whose purpose might not be obvious to those
unfamiliar with the domain?

- **Why a service instead of a controller?**  
The goal is to expose a single capability (obtaining the API client)
without persistent state or controller lifecycle. The [Core data-service
guidelines](https://github.com/MetaMask/core/blob/main/docs/controller-guidelines.md)
and the sample package use a **service** (plain class +
`registerMethodActionHandlers`) for this; the same pattern is used by
`BackendWebSocketService` and `AccountActivityService` in core-backend.

- **Why export query options instead of only fetch methods?**  
UI that uses React Query (or similar) needs the **options object**
(queryKey, queryFn, staleTime, etc.) to plug into `useQuery` /
`useInfiniteQuery` / `useSuspenseQuery`. Exposing it keeps a single
source of truth for keys and behavior and avoids drift between “fetch”
and “hook” usage.

### If your primary goal was to update one package but you found you had
to update another one along the way, why did you do so?

All changes are confined to `@metamask/core-backend`. No other packages
were modified.

### If you had to upgrade a dependency, why did you do so?

No dependency upgrades in this PR.

---

## References

- Fixes: (add issue number if applicable)
- Related: (e.g. consumer PRs that will use `ApiPlatformClientService`
or `get*QueryOptions`)

---

## Checklist

- [x] I've updated the test suite for new or updated code as appropriate
  - Added `ApiPlatformClientService.test.ts`; fixed lint in that file.
- [x] I've updated documentation (JSDoc, Markdown, etc.) for new or
updated code as appropriate
- JSDoc added for all `get*QueryOptions`; service and README already
document usage.
- [x] I've communicated my changes to consumers by [updating changelogs
for packages I've
changed](https://github.com/MetaMask/core/tree/main/docs/processes/updating-changelogs.md)
- `packages/core-backend/CHANGELOG.md`: entries for
ApiPlatformClientService and for exported query options.
- [ ] I've introduced [breaking
changes](https://github.com/MetaMask/core/tree/main/docs/processes/breaking-changes.md)
in this PR and have prepared draft pull requests for clients and
consumer packages to resolve them
  - N/A. No breaking changes.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Medium risk due to multiple public API surface changes (renamed
params, removed methods/options, and altered error semantics) that can
break downstream callers and caching keys if not updated consistently.
> 
> **Overview**
> Introduces `ApiPlatformClientService`, a new messenger-exposed service
that provides a shared `ApiPlatformClient` instance via
`ApiPlatformClientService:getApiPlatformClient`.
> 
> Across `accounts`, `prices`, `token`, and `tokens` clients, adds
`get*QueryOptions` helpers for each endpoint and extends `FetchOptions`
to accept TanStack Query options; `getQueryOptionsOverrides` is
added/exported to merge caller overrides while preserving client-owned
`queryKey`/`queryFn` and consistent `staleTime`/`gcTime` defaults.
> 
> Makes **breaking** API adjustments to align with backend specs: merges
`fetchV2BalancesWithOptions` into `fetchV2Balances`, updates v4
multi-account transactions to use `accountAddresses` and expanded filter
params (removing `includeValueTransfers`), and changes some edge
behavior (short-circuit empty required inputs to return empty results;
relationship and `fetchV1TokenPrice` error paths now throw instead of
returning sentinel values).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
45a8b60. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants