Search code examples
reduxnext.jsrtk-querynext.js13

How to make a post request in Next 13 with app directory and RTK Query


How can I make a POST request to my backend using RTK Query in NextJS 13 from the new api folder?

What is the correct way to trigger a request? I have tried the following 2 ways to dispatch and none of them worked:

//first try
const dispatch = useDispatch<AppDispatch>();
dispatch(addMemoria.initiate({firstName, lastName, birthDate: selectedBirthDate, deathDate: selectedDeathDate}));
//second try
addMemoria.initiate({firstName, lastName, birthDate: selectedBirthDate, deathDate: selectedDeathDate});

The expected outcome would be to have a successful POST request and a new Memoria Entry in the database

The Error I get:

hydration-error-info.js?32aa:27 An unhandled error occurred processing a request for the endpoint "addMemoria".
In the case of an unhandled error, no tags will be "provided" or "invalidated". Error: Invariant: Method expects to have requestAsyncStorage, none available
    at headers (webpack-internal:///(:3000/e-memoria/app-client)/./node_modules/next/dist/client/components/headers.js:17:15)
    at getServerSession (webpack-internal:///(:3000/e-memoria/app-client)/./node_modules/next-auth/next/index.js:94:35)
    at prepareHeaders (webpack-internal:///(:3000/e-memoria/app-client)/./src/store/strapiApi.ts:23:90)
    at eval (webpack-internal:///(:3000/e-memoria/app-client)/./node_modules/@reduxjs/toolkit/dist/query/rtk-query.esm.js:239:42)
    at step (webpack-internal:///(:3000/e-memoria/app-client)/./node_modules/@reduxjs/toolkit/dist/query/rtk-query.esm.js:44:23)
    at Object.eval [as next] (webpack-internal:///(:3000/e-memoria/app-client)/./node_modules/@reduxjs/toolkit/dist/query/rtk-query.esm.js:25:53)

The following post request is valid using my http client:

POST http://localhost:1337/api/memorias
Content-Type: application/json
authorization: Bearer ****************************

{
  "data": {
    "firstName": "FirstNAmeTest",
    "lastName": "LAstNameTest",
    "birthDate": "2021-09-01",
    "deathDate": "2021-09-02"
  }
}

RTK store config:

export const store = configureStore({
  reducer: {
    strapiApi: strapiApi.reducer,
  },
  middleware(getDefaultMiddleware) {
    return getDefaultMiddleware().concat(strapiApi.middleware);
  },
});

export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;

My Api Endpoint (the authorized GET request works):

const baseQuery = fetchBaseQuery({
  baseUrl: process.env.STRAPI_API_URL + '/api/', //"http://localhost:3000/api/",
  prepareHeaders: async (headers, { getState }) => {
    const session : any = await getServerSession(authOptions);
    // If we have a token set in state, let's assume that we should be passing it.
    if (session) {
      headers.set('authorization', `Bearer ${session?.jwt}`)
    }
    headers.set('cache', 'no-store');
    headers.set('Cache-control', 'no-store, max-age=0');

    return headers
  },
})

export const strapiApi = createApi({
  reducerPath: "strapiApi",
  baseQuery: baseQuery,
  tagTypes: ["Memoria", "bla"],
  endpoints: (builder) => ({
    getAllMemorias: builder.query<{ results: Array<{ name: string }> }, void>({
      query: () => `memorias`,
      providesTags: ['bla'],

    }),
    addMemoria: builder.mutation<Memoria, Partial<Memoria>>({
      query: (body: Partial<Memoria>) => ({
        url: `memorias`,
        method: 'POST',
        body: createStrapiPOSTBody(body),
      }),
      invalidatesTags: [{ type: 'Memoria', id: 'LIST' }],
    }),
});

export const { getAllMemorias, addMemoria } = strapiApi.endpoints;

Solution

  • To my knowledge, you can only call getServerSession in React Server Components. You do not have access to headers inside client components that are being rendered on the server. It seems like you are calling it from a client component right now.

    Generally, you should also not use something like a export const for a Redux store in Next SSR, as that store will be shared by multiple users that way. Tbh., there isn't a good story on how to do all of that - it's still very much experimental.