fetchBaseQuery
This is a very small wrapper around fetch that aims to simplify requests. It is not a full-blown replacement for axios, superagent, or any other more heavy-weight library, but it will cover the large majority of your needs.
It takes all standard options from fetch's RequestInit interface, as well as baseUrl, a prepareHeaders function, an optional fetch function, and a paramsSerializer function.
- baseUrl(required)- Typically a string like https://api.your-really-great-app.com/v1/. If you don't provide abaseUrl, it defaults to a relative path from where the request is being made. You should most likely always specify this.
 
- Typically a string like 
- prepareHeaders(optional)- Allows you to inject headers on every request. You can specify headers at the endpoint level, but you'll typically want to set common headers like - authorizationhere. As a convenience mechanism, the second argument allows you to use- getStateto access your redux store in the event you store information you'll need there such as an auth token.
- prepareHeaders signature;(headers: Headers, api: { getState: () => unknown }) => Headers
 
- paramsSerializer(optional)- A function that can be used to apply custom transformations to the data passed into params. If you don't provide this,paramswill be given directly tonew URLSearchParms(). With some API integrations, you may need to leverage this to use something like thequery-stringlibrary to support different array types.
 
- A function that can be used to apply custom transformations to the data passed into 
- fetchFn(optional)- A fetch function that overrides the default on the window. Can be useful in SSR environments where you may need to leverage isomorphic-fetchorcross-fetch.
 
- A fetch function that overrides the default on the window. Can be useful in SSR environments where you may need to leverage 
Promise<{
    data: any;
    error?: undefined;
    meta?: { request: Request; response: Response };
} | {
    error: {
        status: number;
        data: any;
    };
    data?: undefined;
    meta?: { request: Request; response: Response };
}>
Using fetchBaseQuery
To use it, import it when you are creating an API service definition.
- TypeScript
- JavaScript
// Or from '@reduxjs/toolkit/query/react'
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'
export const pokemonApi = createApi({
  baseQuery: fetchBaseQuery({ baseUrl: 'https://pokeapi.co/api/v2/' }), // Set the baseUrl for every endpoint below
  endpoints: (builder) => ({
    getPokemonByName: builder.query({
      query: (name: string) => `pokemon/${name}`, // Will make a request like https://pokeapi.co/api/v2/pokemon/bulbasaur
    }),
    updatePokemon: builder.mutation({
      query: ({ name, patch }) => ({
        url: `pokemon/${name}`,
        method: 'PATCH', // When performing a mutation, you typically use a method of PATCH/PUT/POST/DELETE for REST endpoints
        body: patch, // fetchBaseQuery automatically adds `content-type: application/json` to the Headers and calls `JSON.stringify(patch)`
      }),
    }),
  }),
})
// Or from '@reduxjs/toolkit/query/react'
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'
export const pokemonApi = createApi({
  baseQuery: fetchBaseQuery({ baseUrl: 'https://pokeapi.co/api/v2/' }),
  endpoints: (builder) => ({
    getPokemonByName: builder.query({
      query: (name) => `pokemon/${name}`, // Will make a request like https://pokeapi.co/api/v2/pokemon/bulbasaur
    }),
    updatePokemon: builder.mutation({
      query: ({ name, patch }) => ({
        url: `pokemon/${name}`,
        method: 'PATCH',
        body: patch, // fetchBaseQuery automatically adds `content-type: application/json` to the Headers and calls `JSON.stringify(patch)`
      }),
    }),
  }),
})
Setting default headers on requests
The most common use case for prepareHeaders would be to automatically include authorization headers for your API requests.
- TypeScript
- JavaScript
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 we have a token set in state, let's assume that we should be passing it.
    if (token) {
      headers.set('authorization', `Bearer ${token}`)
    }
    return headers
  },
})
import { fetchBaseQuery } from '@reduxjs/toolkit/query'
const baseQuery = fetchBaseQuery({
  baseUrl: '/',
  prepareHeaders: (headers, { getState }) => {
    const token = getState().auth.token
    // If we have a token set in state, let's assume that we should be passing it.
    if (token) {
      headers.set('authorization', `Bearer ${token}`)
    }
    return headers
  },
})
Individual query options
There is more behavior that you can define on a per-request basis that extends the default options available to the RequestInit interface.
- TypeScript
- JavaScript
interface FetchArgs extends RequestInit {
  url: string
  params?: Record<string, any>
  body?: any
  responseHandler?: 'json' | 'text' | ((response: Response) => Promise<any>)
  validateStatus?: (response: Response, body: any) => boolean
}
const defaultValidateStatus = (response: Response) =>
  response.status >= 200 && response.status <= 299
const defaultValidateStatus = (response) =>
  response.status >= 200 && response.status <= 299
Setting the body
By default, fetchBaseQuery assumes that every request you make will be json, so in those cases all you have to do is set the url and pass a body object when appropriate. For other implementations, you can manually set the Headers to specify the content type.
json
 // omitted
  endpoints: (builder) => ({
    updateUser: builder.query({
      query: (user: Record<string, string>) => ({
        url: `users`,
        method: 'PUT',
        body: user // Body is automatically converted to json with the correct headers
      }),
    }),
text
 // omitted
  endpoints: (builder) => ({
    updateUser: builder.query({
      query: (user: Record<string, string>) => ({
        url: `users`,
        method: 'PUT',
        headers: {
            'content-type': 'text/plain',
        },
        body: user
      }),
    }),
Setting the query string
fetchBaseQuery provides a simple mechanism that converts an object to a serialized query string by passing the object to new URLSearchParms(). If this doesn't suit your needs, you have two options:
- Pass the paramsSerializeroption tofetchBaseQueryto apply custom transformations
- Build your own querystring and set it in the url
 // omitted
  endpoints: (builder) => ({
    updateUser: builder.query({
      query: (user: Record<string, string>) => ({
        url: `users`,
        // Assuming no `paramsSerializer` is specified, the user object is automatically converted
        // and produces a url like /api/users?first_name=test&last_name=example
        params: user
      }),
    }),
Parsing a Response
By default, fetchBaseQuery assumes that every Response you get will be parsed as json. In the event that you don't want that to happen, you can specify an alternative response handler like text, or take complete control and use a custom function that accepts the raw Response object โ allowing you to use any Body method.
- TypeScript
- JavaScript
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'
export const customApi = createApi({
  baseQuery: fetchBaseQuery({ baseUrl: '/api/' }),
  endpoints: (builder) => ({
    getUsers: builder.query({
      query: () => ({
        url: `users`,
        responseHandler: (response) => response.text(), // This is the same as passing 'text'
      }),
    }),
  }),
})
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'
export const customApi = createApi({
  baseQuery: fetchBaseQuery({ baseUrl: '/api/' }),
  endpoints: (builder) => ({
    getUsers: builder.query({
      query: () => ({
        url: `users`,
        responseHandler: (response) => response.text(), // This is the same as passing 'text'
      }),
    }),
  }),
})
Note about responses that return an undefined body
If you make a json request to an API that only returns a 200 with an undefined body, fetchBaseQuery will pass that through as undefined and will not try to parse it as json. This can be common with some APIs, especially on delete requests.
Handling non-standard Response status codes
By default, fetchBaseQuery will reject any Response that does not have a status code of 2xx and set it to error. This is the same behavior you've most likely experienced with axios and other popular libraries. In the event that you have a non-standard API you're dealing with, you can use the validateStatus option to customize this behavior.
- TypeScript
- JavaScript
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'
export const customApi = createApi({
  baseQuery: fetchBaseQuery({ baseUrl: '/api/' }), // Set the baseUrl for every endpoint below
  endpoints: (builder) => ({
    getUsers: builder.query({
      query: () => ({
        url: `users`,
        validateStatus: (response, result) =>
          response.status === 200 && !result.isError, // Our tricky API always returns a 200, but sets an `isError` property when there is an error.
      }),
    }),
  }),
})
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query'
export const customApi = createApi({
  baseQuery: fetchBaseQuery({ baseUrl: '/api/' }),
  endpoints: (builder) => ({
    getUsers: builder.query({
      query: () => ({
        url: `users`,
        validateStatus: (response, result) =>
          response.status === 200 && !result.isError, // Our tricky API always returns a 200, but sets an `isError` property when there is an error.
      }),
    }),
  }),
})