new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Redux Toolkit · RTK Query · all subjects

createapi/basequery

49 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

QueryReturnValue structure

QueryReturnValue is a union type that returns either {error: E, data?: undefined, meta?: M} or {error?: undefined, data: T, meta?: M}. This means a query result must contain either an error or data property, but not both.

baseQuery function arguments and signature

baseQuery receives three parameters: args (the return value of the query function for a given endpoint), api (the BaseQueryApi object containing signal, abort, dispatch, getState, extra, endpoint, type, forced, and queryCacheKey properties), and extraOptions (optional extra options provided for a given endpoint). The baseQuery function signature returns MaybePromise<QueryReturnValue<Result, Error, Meta>>. BaseQueryApi contains: signal (AbortSignal), abort (function), dispatch (ThunkDispatch), getState (function), extra (unknown), endpoint (string), and type ('query' or 'mutation'), and optional forced (boolean).

fetchBaseQuery factory function signature

fetchBaseQuery is a factory function that takes configuration options and returns a data fetching method compatible with RTK Query's baseQuery option. The function type is: type FetchBaseQuery = (args: FetchBaseQueryArgs) => (args: string | FetchArgs, api: BaseQueryApi, extraOptions: ExtraOptions) => FetchBaseQueryResult

FetchBaseQueryArgs configuration parameters

FetchBaseQueryArgs type includes: baseUrl (optional, string), prepareHeaders (optional, function), fetchFn (optional, function), paramsSerializer (optional, function), isJsonContentType (optional, callback), jsonContentType (optional, string), timeout (optional, number), and all standard RequestInit options from the Fetch API.

prepareHeaders function signature and access

The prepareHeaders function receives two arguments: headers (Headers object) and an api object. The api object provides: getState function to access Redux store, arg (string or FetchArgs), extra (unknown), endpoint (string), type ('query' or 'mutation'), and forced (boolean or undefined). The function can mutate headers directly and may return Headers or void.

FetchBaseQueryResult return type

FetchBaseQueryResult is a Promise that resolves to either a success object with data and optional meta (containing request and response), or an error object with error and optional meta. The meta object contains request and response properties when available.

FetchBaseQueryError types

FetchBaseQueryError can be one of five types: (1) HTTP status error with status (number) and data (unknown); (2) FETCH_ERROR with status 'FETCH_ERROR', optional data, and error string; (3) PARSING_ERROR with status 'PARSING_ERROR', originalStatus (number), data (string), and error string; (4) TIMEOUT_ERROR with status 'TIMEOUT_ERROR', optional data, and error string; (5) CUSTOM_ERROR with status 'CUSTOM_ERROR', optional data, and error string.

baseUrl parameter

The baseUrl parameter is required. It should typically be a string like 'https://api.your-really-great-app.com/v1/'. If not provided, it defaults to a relative path from where the request is being made. It is recommended to always specify a baseUrl.

prepareHeaders use cases and benefits

The prepareHeaders option allows injecting headers on every request. While headers can be specified at the endpoint level, prepareHeaders is typically used to set common headers like authorization. It provides access to Redux state via getState, which is useful for storing and retrieving auth tokens or other shared state.

paramsSerializer function purpose

The paramsSerializer function applies custom transformations to data passed into the params property. If not provided, params will be stripped of keys with undefined values and passed to new URLSearchParams(). This option is useful for API integrations that require special array handling or other non-standard query string formats.

fetchFn override option

The fetchFn option allows overriding the default fetch function. This is useful in SSR environments where you may need to use isomorphic-fetch or cross-fetch instead of the native fetch implementation.

timeout parameter behavior

The timeout parameter is a number in milliseconds representing the maximum time a request can take before timing out. By default, fetchBaseQuery has no timeout set, meaning requests will remain pending until the API resolves or the browser's default timeout is reached (typically 5 minutes).

isJsonContentType callback

The isJsonContentType callback receives a Headers object and determines whether the body field should be stringified via JSON.stringify(). The default implementation inspects the content-type header and matches values like 'application/json' and 'application/vnd.api+json'.

jsonContentType parameter

The jsonContentType parameter specifies the content-type header to automatically set for requests with a jsonifiable body that do not have an explicit content-type header. It defaults to 'application/json'.

FetchArgs endpoint request options interface

The FetchArgs interface extends RequestInit and includes: url (string, required), params (optional, Record<string, any>), body (optional, any), responseHandler (optional, 'json' | 'text' | 'content-type' | function), validateStatus (optional, function), and timeout (optional, number).

Default validateStatus behavior

By default, fetchBaseQuery rejects any Response that does not have a status code in the 2xx range (200-299) and sets it to error. This behavior is equivalent to: const defaultValidateStatus = (response: Response) => response.status >= 200 && response.status <= 299

responseHandler field options

The responseHandler field can be: (1) 'json' - uses response.json() method, (2) 'text' - uses response.text() method, (3) 'content-type' - checks the header to determine if JSON or text, then uses the appropriate method, (4) a callback function that receives the raw Response object and returns Promise<any>.

Default responseHandler implementation

The default responseHandler is 'json', equivalent to: const defaultResponseHandler = async (res: Response) => { const text = await res.text(); return text.length ? JSON.parse(text) : null }. This handles cases where responses return undefined body by passing it through as undefined without attempting JSON parsing.

JSON body handling behavior

By default, fetchBaseQuery assumes every request is json. When a body is provided, it is automatically converted to json with the correct headers set (content-type: application/json). The conversion uses JSON.stringify() based on the isJsonContentType check.

Query string parameters conversion

fetchBaseQuery provides a simple mechanism to convert an object to a serialized query string by passing it to new URLSearchParams(). For custom needs, either use the paramsSerializer option to apply custom transformations, or build your own querystring and set it in the url property.

validateStatus custom implementation

The validateStatus option allows customizing whether a response should be treated as success or error. It receives the Response object and the parsed body and returns a boolean. For example, an API that always returns 200 but sets an isError property can validate like: validateStatus: (response, result) => response.status === 200 && !result.isError

Timeout priority when specified at multiple levels

When timeout is specified both on the baseQuery configuration and on individual endpoints, the endpoint value takes priority over the baseQuery timeout value.

Basic fetchBaseQuery usage example

Example showing basic setup with fetchBaseQuery: import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query' export const pokemonApi = createApi({ baseQuery: fetchBaseQuery({ baseUrl: 'https://pokeapi.co/api/v2/' }), endpoints: (build) => ({ getPokemonByName: build.query({ query: (name: string) => `pokemon/${name}`, }), updatePokemon: build.mutation({ query: ({ name, patch }) => ({ url: `pokemon/${name}`, method: 'PATCH', body: patch, }), }), }), })

Setting authorization headers example

Example showing how to set authorization headers from Redux state: import { fetchBaseQuery } from '@reduxjs/toolkit/query' import type { RootState } from './store' const baseQuery = fetchBaseQuery({ baseUrl: '/', prepareHeaders: (headers, { getState }) => { const token = (getState() as RootState).auth.token if (token) { headers.set('authorization', `Bearer ${token}`) } return headers }, })

Parsing response as text example

Example showing how to parse a response as text instead of JSON: import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query' export const customApi = createApi({ baseQuery: fetchBaseQuery({ baseUrl: '/api/' }), endpoints: (build) => ({ getUsers: build.query({ query: () => ({ url: `users`, responseHandler: (response) => response.text(), }), }), }), })

Setting timeout example

Example showing how to set timeout at both baseQuery and endpoint levels: import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query' export const api = createApi({ baseQuery: fetchBaseQuery({ baseUrl: '/api/', timeout: 10000 }), endpoints: (build) => ({ getUsers: build.query({ query: () => ({ url: `users`, timeout: 1000, }), }), }), })

Custom validateStatus example

Example showing how to use custom validateStatus for an API that always returns 200 but sets an isError property: import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query' export const customApi = createApi({ baseQuery: fetchBaseQuery({ baseUrl: '/api/' }), endpoints: (build) => ({ getUsers: build.query({ query: () => ({ url: `users`, validateStatus: (response, result) => response.status === 200 && !result.isError, }), }), }), })

fetchBaseQuery purpose and scope

fetchBaseQuery is a small wrapper around the Fetch API that simplifies HTTP requests. It is designed to cover the vast majority of HTTP request needs but is not a full replacement for heavier libraries like axios or superagent.

RTK Query fetchBaseQuery wrapper

RTK Query ships with a very tiny and flexible fetch wrapper called fetchBaseQuery that can be easily swapped with other HTTP clients such as axios, redaxios, or custom implementations.

RTK Query supports retrying

RTK Query supports automatic retrying of failed requests.

BaseQueryFn type signature and generics

The BaseQueryFn type has the following signature and generic parameters: export type BaseQueryFn<Args = any, Result = unknown, Error = unknown, DefinitionExtraOptions = {}, Meta = {}> = (args: Args, api: BaseQueryApi, extraOptions: DefinitionExtraOptions) => MaybePromise<QueryReturnValue<Result, Error, Meta>> Generic parameters: - Args: type for first parameter, the result from a query property will be passed here - Result: type returned in the data property for success case; keep as unknown unless all queries return same type - Error: type returned for error property; applies to all queryFn functions throughout the API - DefinitionExtraOptions: type for third parameter, value from extraOptions property on endpoint - Meta: type of meta property returned from baseQuery, accessible as second argument to transformResponse and transformErrorResponse BaseQueryApi interface: export interface BaseQueryApi { signal: AbortSignal dispatch: ThunkDispatch<any, any, any> getState: () => unknown }

QueryReturnValue type for success and error cases

QueryReturnValue is a discriminated union type: export type QueryReturnValue<T = unknown, E = unknown, M = unknown> = | { error: E data?: undefined meta?: M } | { error?: undefined data: T meta?: M } Success case: error is undefined, data is T, meta is optional M Error case: error is E, data is undefined, meta is optional M

Meta property from baseQuery is potentially undefined

The meta property returned from a baseQuery will always be considered as potentially undefined, as a throw in the error case may result in it not being provided. When accessing values from the meta property, use optional chaining to account for this.

fetchBaseQuery error type

With fetchBaseQuery, the error type returned is: { status: number data: any }

fakeBaseQuery for queryFn-only APIs without baseQuery

RTK Query provides fakeBaseQuery function for users who want to use only queryFn for each endpoint without including a baseQuery. Call fakeBaseQuery<CustomErrorType>() to specify the error type each queryFn should return.

Example: fakeBaseQuery with custom error type

import { createApi, fakeBaseQuery } from '@reduxjs/toolkit/query' type CustomErrorType = { reason: 'too cold' | 'too hot' } const api = createApi({ baseQuery: fakeBaseQuery<CustomErrorType>(), endpoints: (build) => ({ eatPorridge: build.query<'just right', 1 | 2 | 3>({ queryFn(seat) { if (seat === 1) { return { error: { reason: 'too cold' } } } if (seat === 2) { return { error: { reason: 'too hot' } } } return { data: 'just right' } }, }), microwaveHotPocket: build.query<'delicious!', number>({ queryFn(duration) { if (duration < 110) { return { error: { reason: 'too cold' } } } if (duration > 140) { return { error: { reason: 'too hot' } } } return { data: 'delicious!' } }, }), }), }) This shows using fakeBaseQuery to define custom error types for multiple queryFn endpoints.

FetchBaseQueryError type with all variants

export type FetchBaseQueryError = | { status: number data: unknown } | { status: 'FETCH_ERROR' data?: undefined error: string } | { status: 'PARSING_ERROR' originalStatus: number data: string error: string } | { status: 'CUSTOM_ERROR' data?: unknown error: string } Variants: number status (HTTP), FETCH_ERROR (fetch execution error), PARSING_ERROR (response parsing error), CUSTOM_ERROR (custom error from queryFn)

Error object structure from fetchBaseQuery

Errors returned by fetchBaseQuery hooks have a status property and a data property. You can access them as error.status and error.data.

Custom baseQuery determines error vs data response

Whether a response is returned as data or error is dictated by the baseQuery provided. The choice of baseQuery implementation determines how errors are formatted and returned.

baseQuery function arguments and return types

A baseQuery function is called with three arguments: args (the query parameters), api (containing signal, dispatch, and getState), and extraOptions. It must return an object with either a data or error property, or a promise that resolves to such an object. The function must always catch errors internally and return them in an object—it must never throw. For successful results, return { data: YourData }. For errors, return { error: YourError }.

fetchBaseQuery return types

fetchBaseQuery returns a Promise with either a success object { data: any, error?: undefined, meta?: { request: Request; response: Response } } or an error object { error: { status: number, data: any }, data?: undefined, meta?: { request: Request; response: Response } }. For success: return { data: YourData }. For error: return { error: { status: number, data: YourErrorData } }.

baseQuery example with axios

Example axios-based baseQuery implementation: const axiosBaseQuery = ({ baseUrl } = { baseUrl: '' }) => async ({ url, method, data, params, headers }) => { try { const result = await axios({ url: baseUrl + url, method, data, params, headers }) return { data: result.data } } catch (axiosError) { const err = axiosError as AxiosError return { error: { status: err.response?.status, data: err.response?.data || err.message } } } } This shows a baseQuery accepting args with url, method, data, params, and headers properties.

baseQuery example with GraphQL

Example GraphQL-based baseQuery implementation: const graphqlBaseQuery = ({ baseUrl }) => async ({ body }) => { try { const result = await request(baseUrl, body) return { data: result } } catch (error) { if (error instanceof ClientError) { return { error: { status: error.response.status, data: error } } } return { error: { status: 500, data: error } } } } This shows GraphQL-specific error handling for ClientError instances.

automatic re-authorization by extending fetchBaseQuery

A baseQuery wrapper can detect 401 Unauthorized errors, attempt to refresh authorization tokens, and retry the initial query. When result.error.status === 401, call a refresh endpoint to get a new token, dispatch tokenReceived action, then retry the original query with baseQuery(args, api, extraOptions). If refresh fails, dispatch loggedOut action. This pattern simulates axios-like interceptors.

preventing multiple unauthorized refresh attempts with async-mutex

When multiple requests fail with 401 errors simultaneously, use async-mutex to prevent redundant refresh token calls. Create a mutex, call await mutex.waitForUnlock() before making requests. Inside the 401 error handler, check if (!mutex.isLocked()), acquire the lock, attempt refresh, release the lock in a finally block. Other requests wait for unlock and retry after the first refresh completes.

retry utility for automatic retries

RTK Query exports a retry utility that wraps baseQuery to automatically retry failed requests. It defaults to 5 attempts with exponential backoff. Wrap baseQuery: retry(baseQuery, { maxRetries: 5 }). Can be overridden per endpoint with extraOptions: { maxRetries: 8 }. Call retry.fail(error, meta) to bail out immediately, useful for errors like 401 where retries are guaranteed to fail.

baseQuery with meta information

A baseQuery can include a meta property in its return value for additional request/response metadata like request IDs or timestamps. Success format: { data: YourData, meta: YourMeta }. Error format: { error: YourError, meta: YourMeta }. The meta value is passed to transformResponse and transformErrorResponse as the second argument, enabling conditional response transformation.

constructing dynamic base URL from Redux state

A baseQuery can use api.getState() to access current Redux state and construct dynamic URLs. Example: const projectId = selectProjectId(api.getState()); if (!projectId) return { error: { status: 400, statusText: 'Bad Request', data: 'No project ID received' } }; adjust the URL and call rawBaseQuery with the modified args.

fetchBaseQuery: lightweight fetch wrapper for queries

RTK Query ships with fetchBaseQuery, which is a lightweight fetch wrapper that automatically handles request headers and response parsing in a manner similar to common libraries like axios. It is the general recommendation for query operations.

Give your agent this brain