Skip to content
Advertisement

Can’t upload picture to MongoDb from React frontend

I’m creating a tinder clone, I can create a user fine however I cant upload a picture. The error I get is ValidationError: User validation failed: pictures: Cast to embedded failed for value “‘picture'” at path “pictures”. I’m not sure what I’m doing wrong. The post request seems to fire as excepted with the payload however its when I login when I get the error. So I’m sure this has something to do with initial creation of the account.

create account front and back

import React, { useState } from "react";
import {useHistory } from "react-router-dom";
import axios from "axios";

const CreateAccount = () => {
  const api = "http://localhost:5000/user/create-account";

  const history = useHistory();

  const [firstName, setFirstName] = useState("");
  const [lastName, setLastName] = useState("");
  const [emailAddress, setEmailAddress] = useState("");
  const [password, setPassword] = useState("");
  const [gender, setGender] = useState("Male");
  const [sexualPreference, setSexualPreference] = useState("Straight");
  const [age, setAge] = useState("");
  const [description, setDescription] = useState("");
  const [picture, setPicture] = useState("");

  const account = {
    firstName: firstName,
    lastName: lastName,
    emailAddress: emailAddress,
    password: password,
    gender: gender,
    sexualPreference: sexualPreference,
    age: age,
    description: description,
    pictures: picture
  };

  console.log(account.gender);
  console.log(account.sexualPreference);
  console.log(account.pictures)

  const submit = () => {
    axios
      .post(api, account)
      .then((res) => {
        console.log(res.data);
        history.push({
          pathname: "/",
        });
      })
      .catch((err) => console.log(err));
  };

  const handleSubmit = (event) => {
    event.preventDefault();
    submit();
  };

  return (
    <div>
      <div>
        <h1>Create account</h1>
      </div>
      <form onSubmit={handleSubmit} encType="multipart/form-data">
        <p>First Name</p>
        <input
          id="firstName"
          name="firstName"
          type="firstName"
          onChange={(e) => setFirstName(e.target.value)}
        ></input>
        <p>Last Name</p>
        <input
          id="lastName"
          name="lastName"
          type="lastName"
          onChange={(e) => setLastName(e.target.value)}
        ></input>
        <p>Email Address</p>
        <input
          id="emailAddress"
          name="emailAddress"
          type="emailAddress"
          onChange={(e) => setEmailAddress(e.target.value)}
        ></input>
        <p>Password</p>
        <input
          id="password"
          name="password"
          type="password"
          onChange={(e) => setPassword(e.target.value)}
        ></input>
        <p>Gender</p>
        <select
          id="gender"
          name="gender"
          type="gender"
          onChange={(e) => setGender(e.target.value)}
        >
          <option value="Male">Male</option>
          <option value="Female">Female</option>
        </select>
        <p>Sexual Preference</p>
        <select
          id="sexualPreference"
          name="sexualPreference"
          type="sexualPreference"
          onChange={(e) => setSexualPreference(e.target.value)}
        >
          <option value="Straight" >Straight</option>
          <option value="Gay" >Gay</option>
          <option value="Lesbian" >Lesbian</option>
          <option value="Bisexual" >Bisexual</option>
        </select>
        <p>Age</p>
        <input
          id="age"
          name="age"
          type="age"
          onChange={(e) => setAge(e.target.value)}
        ></input>
        <p>Description</p>
        <input
          id="description"
          name="description"
          type="description"
          onChange={(e) => setDescription(e.target.value)}
        ></input>
        <input 
          type="file" 
          name="file"  
          id="picture" 
          onChange={(e) => setPicture(e.target.id)}
          ></input>
        <button type="submit">Submit</button>
      </form>
    </div>
  );
};

export default CreateAccount;
router.post( "/user/create-account", [
    check("firstName")
      .exists({ checkNull: true, checkFalsy: true })
      .withMessage('Please provide a value for "firstName"'),
    check("lastName")
      .exists({ checkNull: true, checkFalsy: true })
      .withMessage('Please provide a value for "username"'),
    check("emailAddress")
      .exists({ checkNull: true, checkFalsy: true })
      .withMessage('Please provide a value for "emailAddress"'),
    check("password")
      .exists({ checkNull: true, checkFalsy: true })
      .withMessage('Please provide a value for "password"'),
    check("gender")
      .exists({ checkNull: true, checkFalsy: true })
      .withMessage('Please provide a value for "gender"'),
    check("sexualPreference")
      .exists({ checkNull: true, checkFalsy: true })
      .withMessage('Please provide a value for "sexualPreference"'),
    check("age")
      .exists({ checkNull: true, checkFalsy: true })
      .withMessage('Please provide a value for "age"'),
    check("description")
      .exists({ checkNull: true, checkFalsy: true })
      .withMessage('Please provide a value for "description"'),
      check("pictures")
      .exists({ checkNull: true, checkFalsy: true })
      .withMessage('Please provide a value for "pictures"'),
  ],
  asyncHandler(async (req, res, next) => {
    // Attempt to get the validation result from the Request object.
    const errors = validationResult(req);

    // If there are validation errors...
    if (!errors.isEmpty()) {
      // Use the Array `map()` method to get a list of error messages.
      const errorMessages = errors.array().map((error) => error.msg);

      // Return the validation errors to the client.
      return res.status(400).json({ errors: errorMessages });
    }

    //new user request body using mongo model from schema
    const postUser = new User({
      firstName: req.body.firstName,
      lastName: req.body.lastName,
      emailAddress: req.body.emailAddress,
      password: req.body.password,
      gender: req.body.gender,
      sexualPreference: req.body.sexualPreference,
      age: req.body.age,
      description: req.body.description,
      pictures: req.body.pictures
    });

    const userEmail = await User.findOne({
      emailAddress: postUser.emailAddress,
    });

    if (postUser.emailAddress === userEmail) {
      console.log("User with this email already exists");

      return res.status(500).end();
    } else if (postUser) {
      //if true salts the password with bcryptjs
      let salt = await bcryptjs.genSalt(10);
      const hashPass = await bcryptjs.hash(postUser.password, salt);
      console.log(hashPass);
      postUser.password = hashPass;
      postUser.save();

      res.json({ postUser });
      return res.status(201).end();
    } else {
      res.status(400).send({ error: "Error: Account not created" }).end();
    }
  })
);

mongoDb Schema

const mongoose = require('mongoose');

const userSchema = mongoose.Schema( {

    firstName:{
        type: String,
        required: true 
    },
    lastName: {
        type: String,
        require: true
    },
    emailAddress: {
        type: String,
        require: true
    },
    password:{
        type: String,
        required: true 
    },
   gender:{
        type: String,
        required: true 
    },
    sexualPreference: {
        type: String,
        required: true 
    },
    age: {
        type: Number,
        required: true 
    },
    description: {
        type: String,
        required: true 
    },
    pictures: {
        type: [{
            picURL: String,
        }],
    },
    matches: {
        type: [{
            Object
        }],
    },
})

module.exports = mongoose.model('User', userSchema);

login backend and frontend

router.post( "/login", asyncHandler(async (req, res, next) => {
    const userBody = req.body;

    const user = await User.findOne({ emailAddress: req.body.emailAddress });

    if (userBody && user) {
      console.log(user);
      const authenticated = bcryptjs.compare(userBody.password, user.password);
      console.log(authenticated);

      if (authenticated) {
        console.log("match");
        const accessToken = jwt.sign(user.toJSON(), process.env.ACCESS_TOKEN_SECRET, { expiresIn: 86400 });
      
        res.cookie("token", accessToken, { httpOnly: false, maxAge: 86400 });

        res.setHeader('Authorization', 'Bearer '+ accessToken); 

        res.json({ 
          user: user,
          accessToken: accessToken,
          })
          .send()

      } else {
        res.status(403).send({ error: "Login failed: Please try again" }).end();
      }
    } else {
      res.status(403).send({ error: "Login failed: Please try again" }).end();
    }
  })
);
import React, { useState} from "react";
import { useHistory } from "react-router";
import axios from "axios";
import { Link } from "react-router-dom";

const api = 'http://localhost:5000';

export default function Login () {

  const history = useHistory();

  const [ email, setEmail ] = useState("");
  const [ pass, setPassword ] = useState("");
 

  const submit = () => {

    axios.post(`${api}/login`, { emailAddress: email, password: pass }, {withCredentials: true, credentials: 'include'})
    .then(res => {
      localStorage.setItem('jwt', res.data.accessToken);
      history.push({
        pathname: `/user/account/${res.data.user._id}` 
     });
    })
    .catch(err => console.log(err));
  }

  const handleSubmit = (event) => {
    event.preventDefault();
    submit()
  }

  return (
    <div>
      <h1>Login</h1>
      <form onSubmit={handleSubmit}>
        <input
          id="emailAddress"
          name="emailAddress"
          type="text"
          placeholder="emailAddress"
          onChange={(e) => setEmail(e.target.value)}
        />
        <input
          id="password"
          name="password"
          type="password"
          placeholder="Password"
          onChange={(e) => setPassword(e.target.value)}
        />
        <button type="submit">Submit</button>
        <button >Cancel</button>
      </form>
      <p>Don't have a user account?
        <Link to="/user/create-account" >Click here</Link>
        to sign up!
      </p>
    </div>
  );
}


Advertisement

Answer

first of all you can’t upload image like this because you send regular http request if you want to send iamge you need to follow this steps

in the frontend you need to send the request with form data for more info read this blog from mdn what is formData mdn you can do something like that with axios append all of the req body to the formData and add it to the axios add multipart/form-data header

   axios({
     method: "post",
      url: "myurl",
    data: bodyFormData,
    headers: { "Content-Type": "multipart/form-data" },
    })
    .then(function (response) {
     // handle success
    
    })
    .catch(function (response) {
      //handle error
      
     });

in the server you need to upload-files-or-images-to-server-using-nodejs

Advertisement