javascriptreactjsredux-toolkitrtk-query

Why is extraOptions undefined in baseQueryWithReauth when making a request with RTK Query?


I’m using Redux-Toolkit (RTK) Query with fetchBaseQuery and a custom baseQueryWithReauth function for handling authentication. My setup involves checking for authentication and refreshing tokens if necessary.

Here's the relevant code:

baseQuery.js

import { fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import { authApiSlice } from "~/features/api/authApiSlice";

// Create a base query instance
const baseQuery = fetchBaseQuery({
  baseUrl: import.meta.env.VITE_API_BASE_URL,
  credentials: "include",
  prepareHeaders: (headers) => {
    headers.set("x-api-key", localStorage.getItem("apiKey") || '');
    return headers;
  },
});

const baseQueryWithReauth = async (args, api, extraOptions) => {
  console.log('Base Query Args:', args);
  console.log('Extra Options:', extraOptions);

  const shouldSkipAuth = extraOptions?.skipAuth || false;

  let result = await baseQuery(args, api, extraOptions);

  if (!shouldSkipAuth && result.error && result.error.status === 401) {
    const refreshResult = await api.dispatch(
      authApiSlice.endpoints.refreshToken.initiate()
    );

    if (refreshResult.data) {
      result = await baseQuery(args, api, extraOptions);
    } else {
      return refreshResult;
    }
  }

  return result;
};

export { baseQueryWithReauth as baseQuery };

authApiSlice.js

import { createApi } from "@reduxjs/toolkit/query/react";
import { baseQuery } from "~/services/api/baseQuery";

export const authApiSlice = createApi({
  reducerPath: "authApi",
  baseQuery,
  endpoints: (builder) => ({
    login: builder.mutation({
      query: ({ email, password }) => ({
        url: `/auth/login`,
        method: "POST",
        body: { email, password },
        extraOptions: { skipAuth: true }, // Skip auth for login
      }),
    }),
    refreshToken: builder.mutation({
      query: () => ({
        url: `/auth/refresh-token`,
        method: "POST",
      }),
    }),
  }),
});

export const { useLoginMutation } = authApiSlice;

Login.jsx

const [login] = useLoginMutation();

const handleLogin = async (email, password) => {
  try {
    const result = await login({ email, password }).unwrap();
    console.log('Login result:', result);
  } catch (err) {
    console.error('Login error:', err);
  }
};

What I Tried

  1. Log Debugging: I’ve logged the extraOptions in baseQueryWithReauth to verify if it’s being passed correctly.
  2. Endpoint Configuration: I’ve configured extraOptions in the authApiSlice endpoints, specifically for the login endpoint to skip authentication.

What I Expected

  1. I expected that the extraOptions set for the login request would be available in the baseQueryWithReauth function, allowing it to skip the authentication logic for login requests.
  2. Instead, I see extraOptions is undefined in baseQueryWithReauth, which causes issues while login.

Solution

  • The extraOptions are passed to the endpoint defintion, not the endpoint's query or queryFn property.

    export const authApiSlice = createApi({
      reducerPath: "authApi",
      baseQuery,
      endpoints: (builder) => ({
        login: builder.mutation({
          query: ({ email, password }) => ({
            url: `/auth/login`,
            method: "POST",
            body: { email, password },
            // <-- remove from here
          }),
          extraOptions: { skipAuth: true }, // <-- move to here
        }),
        refreshToken: builder.mutation({
          query: () => ({
            url: `/auth/refresh-token`,
            method: "POST",
          }),
        }),
      }),
    });