Home > OS >  req.body undefined from react client to express server
req.body undefined from react client to express server

Time:06-18

Server: NodeJS, Express, Mongoose/MongoDB

Cloud provider: MongoDB

Client: React, mobx, axios

Tested with: body-parser, express.json()

Short question: Controller requests data(string) - userId on certain URL from client, but req.body.userId is always undefined. I've checked every component and console logged every step and every react functional component prop - it's okay.

Everything else works fine, such as: find user on sign in/create on sign up, finding posts by id, adding comments to certain post using is id and so all. Already looked up 10-15 questions about this issue, nothing helped. I need to know in which of these files I've been dumb. Thanks in advance!

Additional info:

Part of server/index.js file:

const app = express()
app.use(corsMiddleware)
app.use(express.json()) //also the body-parser returns the same result
app.use('/api/user', userRouter)

CORS middleware:

function cors(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*")
    res.header("Access-Control-Allow-Methods", "GET, PUT, PATCH, POST, DELETE, OPTIONS")
    res.header("Access-Control-Allow-Headers", "Content-Type, Authorization, Origin, X-Requested-With, Accept, X-Auth-Token")
    
    if (req.method === "OPTIONS") {
        res.status(200)
    }
    next()
}

User model:

const {Schema, model} = require('mongoose')

const User = new Schema({
    email: {type: String, required: true, unique: true},
    login: {type: String, required: true},
    password: {type: String, required: true},
    link: {type: String, required: true},
    avatar: {type: String},
    bio: {type: String},
    status: {type: String, default: 'offline'},
    friends: {type: Array, default: []},
    communities: {type: Array, default: []},
    requests: {type: Object, default: {
        to: [],
        from: []
    }},
    posts: {type: Array, default: []},
    settings: {type: Array, default: []},
    registrationDate: {type: String, default: Date.now()}
})

module.exports = model('User', User )

Post model:

const {Schema, model} = require('mongoose')
const moment = require('moment')

const Post = new Schema({
    title: {type: String, required: true},
    content: {type: String, required: true},
    userId: {type: ObjectId, required: true, ref: 'User'}, //problem here
    login: {type: String, ref: 'User'},
    likes: {type: Array, default: []},
    dislikes: {type: Array, default: []},
    comments: {type: Array, default: []},
    date: {type: String, default: () => {
        return moment().format('D/MM/YYYY hh:mm')
    }}
})

module.exports = model('Post', Post )

Part of userController that gets request:

    async getUserById(req, res) {
        try {
            const {userId} = req.body //tried also const userId = req.body.userId
            console.log(userId) //for debugging, output undefined
            const user = await User.findById(userId)
            res.status(200).json(user)
            console.log(user) //for debugging, output null
        } catch (e) {
            console.log(e) //no errors 
        }
    }
}

Part of user.routes:

router.get('/get', userController.getUserById)
//also deleted the authMiddleware for now, just to make things clean

Client components relations: Feed -> Post -> UserModel

Part of Feed.jsx:

const renderPosts = () => {
        return(
            posts.map((post) => {
                return (
                    <Post
                    key={post._id}
                    username={post.login}
                    title={post.title}
                    text={post.content}
                    likes={post.likes}
                    dislikes={post.dislikes}
                    comments={post.comments}
                    date={post.date}
                    id={post._id}
                    userId={post.userId} //problem here
                    />
                )
            })
        )
}

Part of Post.jsx:

  const [userId, setUserId] = useState('')
  useEffect(() => {
    console.log(`user id passed from Feed ${props.userId}`) //output OK
    setUserId(props.userId)
    console.log(`user id as prop in Post ${userId}`) //output OK
  }, [props.userId]) //I know I don't need to put it to dependencies, just testing

return (
    <div className={styles.Post}>
        <div className={styles['post-user']}>
            <UserModel userId={userId} username={props.username} link='#'/>
            <p className={styles['post-user-title']}>{props.title}</p>
        </div>
   </div>

)

Part of UserModel.jsx:

export default function UserModel(
      {
        username, 
        link,
        reverse, 
        mainUser, 
        onClick, 
        comment, 
        isFriend,
        userId
      }) {

      const handleUsernameClick = async () => {
        userPage.fetchUserData(userId)
        console.log(`model user id ${userId}`) //output is OK
      }  
    return (
        <div className={styles['user-model']}
            {//some unnecessary data here with button that calls handleUsernameClick}
        </div>
    )
  }

Part of mobx file that holds fetchUserData method:

class UserPage {

    constructor() {
        makeAutoObservable(this)
    }

    //some methods here

    fetchUserData = async(userId) => {
        try {
            const user = await axios.get('http://localhost:5000/api/user/get',
            {userId},
            {
                headers:{Authorization: `Bearer ${localStorage.getItem('token')}`},
            })
            this.user = user
            this.setUserPage(
                user.login, 
                user._id, 
                user.link, 
                user.friends, 
                user.communities
                )
            console.log(user) 
            console.log(`user id in store ${userId}`) //output OK
        } catch (e) {
            console.log(e)
        }
    }
}
}

export default new UserPage()

CodePudding user response:

to send data, you need to use POST method

change it throughout:

router.post('/get', userController.getUserById)


await axios.post('http://localhost:5000/api/user/get',
  • Related