Search code examples
reactjsreduxredux-toolkitrtk-query

RTK Query -- protected endpoints with public endpoints


I have a fairly simple application where I want the public to be able to see all posts, but I want the user to be authenticated to create and delete only their post.

When I set it up like this, I get an error, "TypeError: Cannot read properties of null (reading 'token') buildThunks.ts:448" and can't fetch posts until logged in.

I'm fairly new to RTK Query. Is there a way to allow an unauthenticated user to use just getPosts and getPost?

Thanks

export const postApi = createApi({
    reducerPath: "postApi",
    baseQuery: fetchBaseQuery({ baseUrl: "http://localhost:3001",
    prepareHeaders: (headers, { getState }) => {
        const token = ( (getState()).auth.user.token )
        if(token){
            headers.set('authorization', `Bearer ${token}`)
            return headers
        }
    },
    }),
    tagTypes: ["Post"],
    endpoints: (builder) => ({
        getPosts: builder.query({
            query: ()=> ({
                url: "/api/posts",
                method: 'GET'
            }),
            providesTags: ["Post"]
        }),
        getPost: builder.query({
            query: (id) => ({
                url: `/api/posts/:${id}`,
                method: 'GET'
            }),
            providesTags: ['Post']
        }),
        createPost: builder.mutation({
            query: (formData) => ({
                url: "/api/posts",
                method: 'POST',
                body: formData
            }),
            invalidatesTags: ["Post"]
        }),
        deletePost: builder.mutation({
            query: (id) => ({
                url: `/api/posts/${id}`,
                method: 'DELETE',
                body: id
            }),
            invalidatesTags: ["Post"]
            
        })
    })

})

export const { useGetPostsQuery, useGetPostQuery, useCreatePostMutation, useDeletePostMutation } = postApi

Routes

import express from 'express'
import { deletePost, getPost, getPosts, newPost } from '../controllers/Post.js'
import { auth } from '../middleware/auth.js'

const router = express.Router()

//get posts
router.get('/', getPosts)

//get post
router.get('/:id', getPost)

//create psot
router.post('/', auth, newPost)

//delete post
router.delete('/:id', auth, deletePost)

export default router

Solution

  • More of a general JavaScript question to be honest ;)

    You are trying to access getState()).auth.user.token, while state.auth.user in your case is null.

    You can write it as getState()).auth.user?.token, and it will not error and just return undefined if there is no .user property (or it is null).