Search code examples
reactjsredux

GET Posts request return html doc instead of posts on server but not on localhost


I have a mern social media app where user can log in and then are taking to their feed where they can create posts and they are displayed on the feed. Everything works on the localhost but on the server I can log in and see the feed and can even create posts that are being saved to the database but they are not being shown on the feed on there server.

This is the server.js:

const path = require('path');
const express = require('express');
const cors = require('cors');
const fileUpload = require('express-fileupload');
const AuthRoute = require('./routes/AuthRoute.js');
const connectDB = require('./config/db.js');
const colors = require('colors');
const dotenv = require('dotenv');
dotenv.config();

const PostRoute = require('./routes/PostRoute.js');
const UploadRoute = require('./routes/UploadRoute.js');

const PORT = process.env.PORT || 8000;

connectDB();

const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cors());

// Serve frontend
if (process.env.NODE_ENV === 'production') {
  app.use(express.static(path.join(__dirname, '../frontend/build')));

  app.get('*', (req, res) =>
    res.sendFile(
      path.resolve(__dirname, '../', 'frontend', 'build', 'index.html')
    )
  );
} else {
  app.get('/', (req, res) => res.send('Please set to production'));
}

app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}.`.yellow.bold);
});

app.use('/api/auth', AuthRoute);
app.use('/api/posts', PostRoute);
app.use('/api/uploadImages', UploadRoute);

I've tried moving things around but it hasn't changed anything. This is my PostRoutes:

const express = require('express');
const {
  createPost,
  getTimelinePosts,
  getAllPosts,
} = require('../controllers/PostController.js');
const { authUser } = require('../middleware/auth');

const router = express.Router();
console.log('inside am in the routes');
router.post('/createPost', createPost);
router.get('/:id/timeline', getTimelinePosts);
router.get('/getAllPosts', authUser, getAllPosts);
module.exports = router;

Below is where the are initially being called and on the localhost and if I comment out all the code except the useEffect it shows the array of posts in the console but in the server console it shows the html doc.

Here is the file:

import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getTimeLinePosts } from '../../../actions/postAction';
import Post from '../Post/Post.js';
import PulseLoader from 'react-spinners/FadeLoader';

const Posts = () => {
  const dispatch = useDispatch();
  const { user } = useSelector((state) => state.authReducer.authData);
  const { posts, loading, error } = useSelector((state) => state.postReducer);

  useEffect(() => {
    if (error) {
      console.log(error);
    }
    dispatch(getTimeLinePosts(user._id));
  }, [dispatch, user._id]);

  return (
    <div className="Posts">
      {loading ? (
        <div style={{ display: 'flex', justifyContent: 'center' }}>
          <PulseLoader
            color="#485639"
            height={15}
            width={5}
            loading={loading}
          />
        </div>
      ) : posts ? (
        posts.map((post, i) => (
          <Post key={i} post={post} index={i} user={user} />
        ))
      ) : (
        "You haven't shared anything yet."
      )}
    </div>
  );
};

export default Posts;

Here is the postRequest

import axios from 'axios';
//import * as PostsApi from '../api/PostsRequests';

export const getTimeLinePosts = (id) => async (dispatch) => {
  console.log(id);
  const API_URL = '/api/posts/';
  dispatch({ type: 'RETREIVING_START' });
  try {
    //const { data } = await PostsApi.getTimelinePosts(id);
    const { data } = await axios.get(`/api/posts/${id}/timeline`);
    console.log(data);
    dispatch({ type: 'RETREIVING_SUCCESS', data: data });
  } catch (error) {
    dispatch({ type: 'RETREIVING_FAIL' });
    console.log(error);
  }
};

And here is the postReducer

const postReducer = (
  state = { posts: null, loading: false, error: false, uploading: false },
  action
) => {
  switch (action.type) {
    // belongs to PostShare.jsx
    case 'ADDPOST_START':
      return { ...state, error: false, uploading: true };
    case 'ADDPOST_SUCCESS':
      return {
        ...state,
        posts: [action.data, ...state.posts],
        uploading: false,
        error: false,
      };
    case 'ADDPOST_FAIL':
      return { ...state, uploading: false, error: true };
    // belongs to Posts.jsx
    case 'RETREIVING_START':
      return { ...state, loading: true, error: false };
    case 'RETREIVING_SUCCESS':
      return {
        ...state,
        posts: action.data,
        loading: false,
        error: false,
      };
    case 'RETREIVING_FAIL':
      return { ...state, loading: false, error: true };
    default:
      return state;
  }
};

export default postReducer;

Solution

  • Short answer: The lines serving static assets should be placed after all the other routes in the server file.

    Long answer: Please put the following lines

    // Serve frontend
    if (process.env.NODE_ENV === 'production') {
      app.use(express.static(path.join(__dirname, '../frontend/build')));
    
      app.get('*', (req, res) =>
        res.sendFile(
          path.resolve(__dirname, '../', 'frontend', 'build', 'index.html')
        )
      );
    

    after the following lines:

    app.use('/api/auth', AuthRoute);
    app.use('/api/posts', PostRoute);
    app.use('/api/uploadImages', UploadRoute);
    

    Express JS interprets routes based on the order they are written in the server file, therefore the static assets should be served after all the other routes. This should solve the problem you are having.