首页 > 解决方案 > 使用 ReactJS 将对象数组发布到 REST API

问题描述

我正在做一个项目,我需要在我的 API 中发布一个新课程。我用 POSTMAN 对此进行了测试,API 工作得很好,但是当我尝试使用 react fetch 发布数据时,数据已损坏。虽然发送像dishName:“pizza”这样的单个字符串工作得很好并且显示在数据库中,但我无法发送对象数组。我尝试以多种方式做到这一点,例如:

 [
            {
                "quantity": 1,
                "unit": "",
                "description": "egg"
            },
            {
                "quantity": 0.5,
                "unit": "cup",
                "description": "mozzarella shredded"
            }
]

或者:

                {
                "quantity": 1,
                "unit": "",
                "description": "egg"
            },
            {
                "quantity": 0.5,
                "unit": "cup",
                "description": "mozzarella shredded"
            }

还有很多很多的组合,但我失败了。

这是我的 React 类,它负责向 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>
  );
}

当我发送数据时,我没有收到任何错误。当我单击在 MongoDB 中展开其元素时,或者在标签的情况下,它甚至没有出现在 MongoDB 中时,只有一组成分是空的。

你能告诉我如何解决这个问题,或者是我做错了什么吗?我搜索了很多答案,但 2 小时后我发现没有任何用处。

编辑:我正在为新课程添加我的 REST API 发布方法:

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`,
    ])
  );

以及新课程的架构:

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;

标签: reactjsmongodbapirestexpress

解决方案


您将ingredients状态设置为字符串,因此您基本上是“字符串化”一个字符串,这将导致JSON SyntaxError. 如果要以这种方式发送数组,则必须指定数组括号[]使其成为有效数组。

要解决它,只需更改:


      <input
        type="text"
        onChange={e => setingredients(e.target.value)}
        className="form-control"
        placeholder='{"quantity": int, "unit": "", "description": ""}'
      />

您需要将其更改为:


      <input
        type="text"
        //parse the string input
        onChange={e => setingredients(JSON.parse(e.target.value))}
        className="form-control"
        //notice the array bracket '[' and ']'
        placeholder='[{"quantity": int, "unit": "", "description": ""}, {"quantity": int, "unit": "", "description": ""}]'
      />

推荐阅读