3

I am using RTK Query for fetching and Caching the data in plain javascript(without react)in nodejs environment. enter image description here I am using the above code which is found in the official website of Redux toolkit. The only change is I included fetchFn in fetchBaseQuery because the node-fetch is not detected as a default function. While I am trying to do it, I am facing this error which says An unhandled error occurred processing a request for the endpoint getPokemonByName In case of an unhandled error, no tags will be "provided" or "invalidated". ReferenceError : Headers is not defined

I don't know how exactly to pass the my own custom fucntion as fetchFn to fetchBaseQuery. I am not sure about the difference between fetchFn and queryFn in createApi. It would be really great if someone can help me out with

  1. Using creatApi with a custom function which takes in url and options as inputs and fetches the data
  2. Using selectors to print the fetched data without using hooks
  • Have you imported fetch from 'node-fetch'? Rtk-query uses fetch internally, and fetch is a browser api and not callable from nodejs. I'm guessing rtk-query also creates headers using new Headers({...}). So in order for rtk query to be nodejs compatible you'd need to add fetch and Headers to your global scope – Matti Sig Jul 23 '23 at 22:12

2 Answers2

0

The fetch api is native to the browser and not available in nodejs. The error you are seeing is due to rtk-query being reliant on the fetch api. In order to make use of the fetch api, you need to polyfill it globally in your project so that the rtk library can make use of it the same way it would in the browser

One way to do that can be seen below

import fetch, { Headers } from 'node-fetch'

globalThis.fetch = fetch;
globalThis.Headers = Headers;
Matti Sig
  • 311
  • 1
  • 5
  • Answer needs supporting information Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](https://stackoverflow.com/help/how-to-answer). – moken Jul 24 '23 at 08:00
  • @moken is's fixed – Matti Sig Jul 24 '23 at 08:27
0

Here is a working example of how to get rtk-query to run in nodejs

Here is a list of things that are crucial to get this working in nodejs

  1. polyfill window.fetch for nodejs
  2. custom settings prop { fetchFn } to the fetchBaseQuery
  3. using rtk-query without hooks means spreading the store around and dispatching to it the predifined actions of rtk-query such as api.endpoints.getCharacters.initiate()

index.js

import { getCharacters } from "./store/characterService.js";
import fetch, { Headers, Request } from "node-fetch";

globalThis.fetch = fetch;
globalThis.Headers = Headers;
globalThis.Request = Request;

const init = async () => {
  const data = await getCharacters();

  console.log(data);
};

init();

store.js

import redux from "@reduxjs/toolkit";
import reduxQuery from "@reduxjs/toolkit/dist/query/index.js";
import fetch from "node-fetch";

export const api = reduxQuery.createApi({
  reducerPath: "api",
  baseQuery: reduxQuery.fetchBaseQuery({
    baseUrl: "https://rickandmortyapi.com/api",
    fetchFn: (...args) => {
      return fetch(...args);
    },
  }),
  endpoints: (builder) => ({
    getCharacters: builder.query({
      query: () => "/character",
    }),
    getCharacter: builder.query({
      query: (id) => `/character/${id}`,
    }),
  }),
});

let store = null;

const initiateStore = () => {
  store = redux.configureStore({
    reducer: {
      [api.reducerPath]: api.reducer,
    },
    middleware: (getDefaultMiddleware) =>
      getDefaultMiddleware().concat(api.middleware),
  });
};

export const getStore = () => {
  if (!store) {
    console.log(store);
    initiateStore();
  }
  return store;
};

characterService.js

import { getStore, api } from "./store.js";

export const getCharacters = async () => {
  const store = getStore();
  const { data } = await store.dispatch(api.endpoints.getCharacters.initiate());
  return data;
};

export const getCharacter = async (id) => {
  const store = getStore();
  const { data } = await store.dispatch(
    api.endpoints.getCharacter.initiate(id)
  );
  return data;
};

Also fetchFn is a property to configure BaseQuery, queryFn is a property to configure individual endpoints and overwrites the settings for BaseQuery for that endpoint

Matti Sig
  • 311
  • 1
  • 5