1

My problem is that I receive a validation error on my server when trying to update my user and product collection in mongodb using formik on my front end.

I add a new product as logged in user. All of the authentication is working with JWT token.

"ValidationError: Product validation failed: title: Path title is required., description: Path description is required., price: Path price is required., location: Path location is required., condition: Path condition is required., category: Path category is required."

I've looked everywhere on stack of, and tried everything for 30+ hours. If anyone could help, I'd appreciate it. I feel bad for asking this novice question, but I've been struggling.

Here is my front end code using formik and axios :

const schema = yup.object().shape({
title: yup.string().required('Title is required'),
description: yup.string().required('Description is required'),
price: yup.number().required('Price is required').positive('Price must be a positive number'),
location: yup.string().required('Location is required'),
condition: yup.string().required('Condition is required'),
category: yup.string().required('Category is required'),
});
const addProductFormik = useFormik({
initialValues: {
title: "",
description: "",
price: "",
location: "",
condition: "",
category: "",
},
validationSchema: schema,
onSubmit: async (values) =\> {
try {
const formData = new FormData();
formData.append('title', values.title);
formData.append('description', values.description);
formData.append('price', values.price);
formData.append('location', values.location);
formData.append('condition', values.condition);
formData.append('category', values.category);

        console.log(formData.get('title'));
        console.log(formData.get('price'));
        
        const url = `http://localhost:3005/product/${user._id}/add-product`;
        
        const config = {
          headers: { Authorization: 'Bearer ' + token }
        };
        console.log(config);
        
        const response = await axios.post(url, formData, config);
        console.log(response);
        const newProduct = response.data.product;
        console.log(newProduct);
        // dispatch(addProduct(newProduct));
      } catch (error) {
        console.log(error)
        console.error(error);
      }
    },

});

Here is my controller function to update my mongo database :

export const createProduct = async (req, res, next) => {
  try {
    const id = req.params.userId;
    const user = await User.findById(id);
    if (!user) {
      return res.status(404).json({ message: "User not found" });
    }
    console.log('user was found')
  
        const createdProduct = new Product({
          title: req.body.title,
          description: req.body.description,
          price: req.body.price,
          location: req.body.location,
          condition: req.body.condition,
          category: req.body.category,
        });
        
        console.log(createdProduct);

  
        console.log('product was created')
        console.log(createdProduct._id);
        try {
          createdProduct.save();
          user.products.push(createdProduct._id);
          Product.insertMany(createdProduct);


          // JWT token signing
      const token = jwt.sign({ userId: user.id }, 'supersecretkey', { expiresIn: '1h' });
      res.status(201).json({ product: createdProduct, token });       
        } catch (err) {
          const error = new HttpError(
            'Creating product failed, please try again.',
            500
          );
          return next(error);          
        }
        console.log('controller function works!');
  } catch (error) {
    console.error(error)
    res.status(404).json({ message: error.message });
  }
};

Here is my Product Schema :

import mongoose from "mongoose";
const Schema = mongoose.Schema;

const ProductSchema = new Schema({
  title: {
    type: String,
    required: true,
  },
  description: {
    type: String,
    required: true,
  },
  price: {
    type: Number,
    required: true,
  },
  location: {
    type: String,
    required: true,
  },
  condition: {
    type: String,
    required: true,
  },
  category: {
    type: String,
    required: true,
    enum: ["Cars", "Electronics", "Clothing", "Furniture", "Other"],
  },
  seller: {
    type: Schema.Types.ObjectId,
    ref: "User",
  },
  createdAt: {
    type: Date,
    default: Date.now,
  },
});

const Product = mongoose.model("Product", ProductSchema);
export default Product;
Here is my User Schema : 

import mongoose from "mongoose";
const Schema = mongoose.Schema;

const UserSchema = new Schema({
  firstName: {
    type: String,
    required: true,
    min: 2,
    max: 50,
  },
  lastName: {
    type: String,
    required: true,
    min: 2,
    max: 50,
  },
  email: {
    type: String,
    required: true,
    unique: true,
  },
  password: {
    type: String,
    required: true,
  },
  location: {
    type: String,
    required: true,
  },
  products: [
    {
      type: Schema.Types.ObjectId,
      ref: "Product",
    },
  ],
  createdAt: {
    type: Date,
    default: Date.now,
  },
});

const User = mongoose.model("User", UserSchema);
export default User

Now when I submit the form, there is no error on the front end. I get a 201 response and when I console log the newProduct in the addProductFormik, this is what it says :

_id: '63f27485ed59ed8c6fdff654', createdAt: '2023-02-19T19:12:05.981Z'} createdAt: "2023-02-19T19:12:05.981Z" _id: "63f27485ed59ed8c6fdff654"

On the back end, i get this error : "ValidationError: Product validation failed: title: Path title is required., description: Path description is required., price: Path price is required., location: Path location is required., condition: Path condition is required., category: Path category is required."

Now if you look at the console logs made in the controller function, these are the console logs that are logged on the server,

user was found

{
  _id: new ObjectId("63f27485ed59ed8c6fdff654"),
  createdAt: 2023-02-19T19:12:05.981Z
}

product was created

new ObjectId("63f27485ed59ed8c6fdff654")

controller function works!

So within my controller function, it finds the user in params, the createdProduct is only shown as a new ObjectId and not with all of its fields (title, description, price, etc). Somehow, it makes it through all the try blocks and console logs the controller function works. But my products collection and user collection (user.products) is not updated and I get that validation error.

1 Answers1

3

Since you're using formData, you need to pass in the Content-Type through Axios headers when posting:

headers: { "Content-Type": "multipart/form-data" },

The default type is application/xml which won't work with your data.

You'll also need to make sure your backend is configured to handle that data coming in. body-parser is commonly used for this with Express.

Here's a simple configuration:

const express = require('express')
const bodyParser = require('body-parser')

const app = express()

// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))

// parse application/json
app.use(bodyParser.json({ limit: '10mb' ))
Wesley LeMahieu
  • 2,296
  • 1
  • 12
  • 8
  • Hi @WesleyLeMahieu, thank you for your input. I changed it, however the same error still persists :( – novicecoder Feb 19 '23 at 19:55
  • What does your entire express entry point look like? Do you have a `body-parser`? What does `console.log(req.body)` output? – Wesley LeMahieu Feb 19 '23 at 20:00
  • I do have a body parser in my entry point : app.use(bodyParser.urlencoded({ limit: "30mb", extended: true })); When I console.log req.body in my controller function, the output is only '{}' upon submitting the formik,. – novicecoder Feb 19 '23 at 20:09
  • 1
    Please, take a look at this [Stackoverflow question](https://stackoverflow.com/questions/24800511/express-js-form-data). I think it will help you to resolve your issue. – Dmitrii Tkachenko Feb 19 '23 at 20:11
  • Where is the route defined for your handler `createProduct` ? What does the route definition look like entirely? Since your backend is not getting data inside `req.body`, but your form appears to be submitting it correctly, I suspect your route. – Wesley LeMahieu Feb 19 '23 at 20:11
  • @WesleyLeMahieu, here is my route, router.post("/:userId/add-product", checkAuth, createProduct);check-auth works fine. and in my formik : const url = `http://localhost:3005/product/${user._id}/add-product`; the port on server is 3005 this is in my app.js file in backend : app.use("/product",productRoutes); – novicecoder Feb 19 '23 at 20:24