I am working on a project in which I need to post a new Course to my API. I tested this with POSTMAN and API works just fine, however when I try to post data using react fetch data is corrupted. While sending single strings like dishName: "pizza" works just fine and is shown in database I cannot manage to send an array of objects. I tried to do it in many ways like:
[
{
"quantity": 1,
"unit": "",
"description": "egg"
},
{
"quantity": 0.5,
"unit": "cup",
"description": "mozzarella shredded"
}
]
or:
{
"quantity": 1,
"unit": "",
"description": "egg"
},
{
"quantity": 0.5,
"unit": "cup",
"description": "mozzarella shredded"
}
and many, many more combinations but I failed.
Here is my React class which is responsible for sending data to API:
import React, { useState } from "react";
import { useHistory } from "react-router-dom";
export default function Login() {
const [dishName, setdishName] = useState("");
const [category, setcategory] = useState("");
const [author, setauthor] = useState("");
const [ingredients, setingredients] = useState([]);
const [cookingTime, setcookingTime] = useState("");
const [sourceUrl, setsourceUrl] = useState("");
const [imageUrl, setimageUrl] = useState("");
const [isPublished, setisPublished] = useState("true");
const [price, setprice] = useState("");
const [tags, settags] = useState([]);
const history = useHistory();
async function login() {
let item = {
dishName,
category,
author,
ingredients,
cookingTime,
sourceUrl,
imageUrl,
isPublished,
price,
tags,
};
await fetch("http://localhost:1234/api/courses", {
method: "POST",
body: JSON.stringify(item),
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
});
history.push("/addCourse");
// window.location.reload();
}
return (
<div className="col-sm-6" style={{ textAlign: "center" }}>
<h1 className="bigBar">Create new recipe</h1>
<input
type="text"
onChange={e => setdishName(e.target.value)}
className="form-control"
placeholder="dishName"
/>
<br />
<input
type="text"
onChange={e => setcategory(e.target.value)}
className="form-control"
placeholder="cathegory"
/>
<br />
<input
type="text"
onChange={e => setauthor(e.target.value)}
className="form-control"
placeholder="author"
/>
<br />
<input
type="text"
onChange={e => setingredients(e.target.value)}
className="form-control"
placeholder='{"quantity": int, "unit": "", "description": ""}'
/>
<br />
<input
type="text"
onChange={e => setcookingTime(e.target.value)}
className="form-control"
placeholder="cooking time"
/>
<br />
<input
type="text"
onChange={e => setsourceUrl(e.target.value)}
className="form-control"
placeholder="source url"
/>
<br />
<input
type="text"
onChange={e => setimageUrl(e.target.value)}
className="form-control"
placeholder="image url"
/>
<br />
<input
type="text"
onChange={e => setisPublished(e.target.value)}
className="form-control"
placeholder="publish status (dafault: true)"
/>
<br />
<input
type="text"
onChange={e => setprice(e.target.value)}
className="form-control"
placeholder="price"
/>
<br />
<input
type="text"
onChange={e => settags(e.target.value)}
className="form-control"
placeholder="tags"
/>
<br />
<button onClick={login} className="btn btn-primary">
Sign up
</button>
</div>
);
}
When I send data I get no error. There is simply an array of Ingredients which is empty when I click ot unfold its elements in MongoDB or in the case of Tags it doesn't even appear in MongoDB.
Could you please tell me how can I fix this or if it is me who is doing something wrong? I searched a lot for an answer but after 2 hours I found nothing useful.
EDIT: I am adding my REST API post method for new Courses:
router.post("/", async (req, res) => {
const { error } = validateCourse(req.body);
if (error)
// 400 Bad request
return res.status(400).send(error.details[0].message);
let course = new Course(
_.pick(req.body, [
`dishName`,
`category`,
`author`,
`ingredients`,
`cookingTime`,
`sourceUrl`,
`imageUrl`,
`isPublished`,
`price`,
// `tags`,
])
);
And schema for new Courses:
const mongoose = require(`mongoose`);
const Joi = require(`joi`);
function validateCourse(body) {
const schema = Joi.object({
dishName: Joi.string().min(3).required(),
category: Joi.string().min(3).required(),
author: Joi.string().min(3).required(),
ingredients: Joi.required(),
cookingTime: Joi.number().min(0).required(),
sourceUrl: Joi.string().required(),
imageUrl: Joi.string().required(),
isPublished: Joi.boolean().required(),
price: Joi.number().min(0).required(),
tags: Joi.required(),
date: Joi.allow(),
});
return schema.validate(body);
}
const Course = mongoose.model(
`Course`,
new mongoose.Schema({
dishName: { type: String, required: true, minLength: 3, maxLength: 255 },
category: {
type: String,
required: true,
lowercase: true,
trim: true,
dishType: [
"carrot",
"broccoli",
"asparagus",
"cauliflower",
"corn",
"cucumber",
"green pepper",
"lettuce",
"mushrooms",
"onion",
"potato",
"pumpkin",
"red pepper",
"tomato",
"beetroot",
"brussel sprouts",
"peas",
"zucchini",
"radish",
"sweet potato",
"artichoke",
"leek",
"cabbage",
"celery",
"chili",
"garlic",
"basil",
"coriander",
"parsley",
"dill",
"rosemary",
"oregano",
"cinnamon",
"saffron",
"green bean",
"bean",
"chickpea",
"lentil",
"apple",
"apricot",
"avocado",
"banana",
"blackberry",
"blackcurrant",
"blueberry",
"boysenberry",
"cherry",
"coconut",
"fig",
"grape",
"grapefruit",
"kiwifruit",
"lemon",
"lime",
"lychee",
"mandarin",
"mango",
"melon",
"nectarine",
"orange",
"papaya",
"passion fruit",
"peach",
"pear",
"pineapple",
"plum",
"pomegranate",
"quince",
"raspberry",
"strawberry",
"watermelon",
"salad",
"pizza",
"pasta",
"popcorn",
"lobster",
"steak",
"bbq",
"pudding",
"hamburger",
"pie",
"cake",
"sausage",
"Tacos",
"Kebab",
"poutine",
"seafood",
"chips",
"fries",
"masala",
"paella",
"som tam",
"chicken",
"toast",
"marzipan",
"tofu",
"Ketchup",
"hummus",
"chili",
"maple syrup",
"parma ham",
"fajitas",
"champ",
"lasagna",
"poke",
"chocolate",
"croissant",
"arepas",
"bunny chow",
"pierogi",
"donuts",
"rendang",
"sushi",
"ice cream",
"duck",
"curry",
"beef",
"goat",
"lamb",
"turkey",
"pork",
"fish",
"crab",
"bacon",
"ham",
"pepperoni",
"salami",
"ribs",
"other",
],
},
author: String,
ingredients: [
{
quantity: Number,
unit: String,
description: String,
},
],
cookingTime: { type: Number, required: true },
sourceUrl: String,
imageUrl: String,
date: { type: Date, default: Date.now },
isPublished: { type: Boolean, default: true },
price: {
type: Number,
required: function () {
return this.isPublished;
},
},
tags: {
type: Array,
validate: {
validator: function (v) {
return v && v.length > 0;
},
message: `A course should have at least one tag.`,
},
},
})
);
exports.Course = Course;
exports.validateCourse = validateCourse;