-2

I am currently working on social media mern stack react app. I am using node js and express as my backend services , also using mongoose to store my data and axios and redux thunk which connect the backend to the front end. Till now I had no issue recieving and sending data to the server. Right now I am trying to create search post get request ,base on a keyword the user entered. The issue with it, that when I am sending the keyword to the server instead of recieving the string it gets undefined value, like redux thunk not sending anything. I will be very thankful if someone could help me with that. I am watching the code over and over again and can't find out the reason for that.

My post controller class(I copied only the relevant function):

import express from "express";
const app = express();
import Post from "../model/PostModel.js";
import ErrorHandlng from "../utilities/ErrorHandling.js";
import bodyParser from "body-parser";
import catchAsync from "../utilities/CatchAsync.js";
import User from "../model/UserModel.js";
app.use(express.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

export const getPosts = catchAsync(async (req, res, next) => {
  const data = req.body.keyword;
  const page = parseInt(req.query.page || "0");
  const PAGE_SIZE = 20;
  const query = new RegExp(data, "i");
  const total = await Post.countDocuments({});
  const posts = await Post.find({ $or: [{ title: query }, { content: query }] })
    .limit(PAGE_SIZE)
    .skip(PAGE_SIZE * page);
  if (!posts) {
    return next(new ErrorHandlng("No posts were found", 400));
  }
  res.status(200).json({
    status: "success",
    data: {
      totalPages: Math.ceil(total / PAGE_SIZE),
      posts,
    },
  });
});

My api class(front end,copied only the calling for that specific get request):

import axios from "axios";
const baseURL = "http://localhost:8000";
axios.defaults.withCredentials = true;
const API = axios.create({
  baseURL,
  credentials: "include",
  headers: {
    Accept: "application/json",
    "Content-Type": "application/json",
  },
});
export const getPostsByKeyword = (keyword, page) =>
  API.get(`/post/getPostsByKey?page=${page}`, keyword);

Post slice class:

export const fetchPostsByKeyWord = createAsyncThunk(
  "post/getKeyword",
  async ({ keyword, page }, { fulfillWithValue, rejectWithValue }) => {
    try {
      const response = await api.getPostsByKeyword(keyword, page);
      if (response.statusCode === "400") {
        throw new Error("There are no available posts");
      }
      const fetchData = await response.data.data.posts;
      const totalPages = await response.data.data.totalPages;
      return fulfillWithValue({ fetchData, totalPages });
    } catch (err) {
      console.log(err.response.message);
    }
  }
);
const initialState = { status: "undefined" };
const PostSlice = createSlice({
  name: "post",
  initialState,
  reducers: {},
  extraReducers: {},
});
export const postActions = PostSlice.actions;
export default PostSlice;

Calling the backend:

dispatch(fetchPostsByKeyWord({ keyword, page }))
  .unwrap()
  .then((originalPromiseResults) => {
    console.log("thte " + " " + originalPromiseResults.totalPages);
    console.log("The data is" + originalPromiseResults.fetchData);
    setTotalPages(originalPromiseResults.totalPages);
  })
  .catch((err) => {
    console.log(err.message);
  });

As you can see I have not copied the whole code, I copied only the parts that are relevants for the question.

Phil
  • 157,677
  • 23
  • 242
  • 245
Jogn1522
  • 3
  • 3
  • You're doubling up on body parsing middleware. Don't do that. You don't need anything from `body-parser`, just `express.json()` and `express.urlencoded()` – Phil Nov 28 '22 at 22:41

1 Answers1

1

Browsers cannot currently send GET requests with a request body. XMLHttpRequest (which Axios uses) will ignore it and fetch() will trigger an error.

See also HTTP GET with request body for extra discussion on why trying this might be a bad idea.

You should instead pass everything required in the query string, preferably via the params option so it is correctly encoded...

export const getPostsByKeyword = (keyword, page) =>
  API.get("/post/getPostsByKey", { params: { page, keyword } });

and grab the data via req.query server-side.

const { page, keyword } = req.query;

With vanilla JS, you can use URLSearchParams to construct the query string...

const params = new URLSearchParams({ page, keyword });

// XHR
const xhr = new XMLHttpRequest();
xhr.open("GET", `/post/getPostsByKey?${params}`);

// Fetch
fetch(`/post/getPostsByKey?${params}`); // GET is the default method

Your Axios instance creation could also be a lot simpler...

  1. Axios is usually quite good at setting the correct content-type header, you don't have to
  2. Your Express app isn't doing any content-negotiation so you don't need to set the accept header
  3. Unless you're actually using cookies (which it doesn't look like), you don't need credential support
const API = axios.create({ baseURL });
Phil
  • 157,677
  • 23
  • 242
  • 245
  • Thank you so much ! I manage to fix it in minutes, with your solution. Can I write body instead of params an it's still work? – Jogn1522 Nov 29 '22 at 09:23
  • @Jogn1522 no. For one, Axios doesn't even have a `body` option, it uses `data`. And secondly, I thought I was pretty clear in that you **cannot** send a request body / data / payload with a GET request – Phil Nov 29 '22 at 09:25
  • Hey thanks, it is so wierd because with all of the second get requests it dies work – Jogn1522 Nov 30 '22 at 09:52