0

I am using a call to new FormData(). The network tab shows that the payload is correct. In the console I am getting the following error:

{message: "Blog validation failed: title: Path `title` is required., postBody: Path `postBody` is required."}

However, in the network tab it's showing that the title and postBody fields are being sent:

Network tab headers output

The server is written with nodejs and is using mongodb. All the routes are working on the backend when testing. Data is posted fine when testing it using a .rest file, but I'm still new to node so I'll post my handler for the post route as well:

router.post('/', async (req, res) => {
    const blogPost = new Blog({
        title: req.body.title,
        author: req.body.author,
        postBody: req.body.postBody,
        postDate: req.body.postDate
    })
    try {
        const newPost = await blogPost.save();
        res.status(201).json(newPost);
    } catch (err) {
        res.status(400).json({ message: err.message })
    }
})

Like I said, when making calls to this route directly using a .rest file everything works fine.

Here's my form submit handler on the frontend:

handleSubmit = (event) => {
    event.preventDefault();
    const data = new FormData(event.target);

    console.log(event.target);
    console.log(data);
    console.log(event.target.postBody.value);

    fetch('http://localhost:4000/blog', {
      method: 'POST',
      mode: 'cors',
      body: data
    })
    .then(res => res.json())
    .then(err => console.error(err))
  }

Maybe I misunderstand the usage of new FormData()?

Isaac
  • 59
  • 8

3 Answers3

0

Ok so when I added body-parser I was still getting the same error. Not sure what I'm doing wrong tbh. However, in the interest of my own time in dealing with this I came up with another solution. I am accepting json in my node app via app.use(express.json())

In the end, I just needed to send headers with the content type and I'm no longer using FormData(). My updated form submit handler (working):

handleSubmit = (event) => {
    event.preventDefault();
    const data = new FormData(event.target);
    const body = event.target.postBody.value;
    const postTitle = event.target.title.value;

    console.log(event.target);
    console.log(data);
    console.log(event.target.postBody.value);

    fetch('http://localhost:4000/blog', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      mode: 'cors',
      body: JSON.stringify({
        title: postTitle,
        postBody: body
      })
    })
    .then(res => res.json())
    .then(err => console.error(err))
  }

This works for me and it's what I'm going with for now so that I can move forward, however, it still does not answer why the formData() method I tried previously was not working, even after using body-parser, as was suggested here.

Isaac
  • 59
  • 8
  • The answer lies in your XHR's `content-type` (`multipart/form-data`). You need some middleware to parse `multipart/form-data` requests. Unfortunately, `body-parser` doesn't parse these types of requests. Instead you'll want to look into multer: https://github.com/expressjs/multer or something similar. For more information, see this stackoverflow question: https://stackoverflow.com/questions/37630419/how-to-handle-formdata-from-express-4 – Matt Carlotta Jan 09 '20 at 01:31
  • @MattCarlotta thanks for the info, I'll look into this. Would you happen to know why it works then without the middleware when I do my fetch call as I did above? – Isaac Jan 09 '20 at 01:34
  • You're using `application/json`, which `body-parser` and/or `express` can parse. This is actually recommended, as `FormData` is mostly useful for uploading files (with or without extra field data). – Matt Carlotta Jan 09 '20 at 01:35
  • On a side note, if you want less of a verbose experience, I'd recommend using axios: https://www.npmjs.com/package/axios over `fetch`. Axios handles the request content-types, automatically parses JSON, can be configured to have a base url (for example, the option to attach `http://localhost:4000/` to every request, so you don't have to), and has great browser support. In general, I find it much more developer friendly. – Matt Carlotta Jan 09 '20 at 01:47
  • Gotcha, thanks for that bit of info too. Good to know about FormData being more useful for uploading files, as I'm building a custom bb editor and file uploading is on my to do list at some point. I have heard of axios, mostly this is all just a learning exercise so I didn't really want to add too many different things into the project. – Isaac Jan 09 '20 at 01:55
  • @MattCarlotta firstly thank you for the down vote and secondly multer is used for file uploads that was not mentioned in the question. As of using FormData, is primarily used for... well, form data (key value pairs). Read the documentation here -> https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects. Isaac needed the body parser for the backed and if that wasn't enough front end needed some tweaking. – tiborK Jan 09 '20 at 16:16
  • @Isaac learning can be overwhelming but learning how to read the documentation will help you big time down the road. Good luck and happy coding. – tiborK Jan 09 '20 at 16:20
  • @tiborK An invalid answer can hinder not only the poster's learning experience, but also those who use search engines to find answers to same question. In addition, `Form Data` is mainly used for key-value pairs involving files (as shown in the MDN). Otherwise, a simple `Map` object for primitives will do the trick: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map – Matt Carlotta Jan 09 '20 at 16:44
  • @MattCarlotta how can you say it is invalid? body-parser is needed on the backend to retrieve the data. You are on the other hand creating an other issue which was not addressed in the question. I'm not here to argue, I'm here to help people solve their problems. – tiborK Jan 09 '20 at 16:52
  • @tiborK Not trying to argue. However, just stating that `body-parser` won't parse `multipart/form-data`. – Matt Carlotta Jan 09 '20 at 18:02
  • @MattCarlotta That is correct. Isaac did not want to upload multipart (which is a file or multiple files). – tiborK Jan 09 '20 at 18:40
  • @tiborK He was using `FormData` in his original post, which requires the `content-type` of the request to be `multipart/form-data` (see his screenshot above). As such, body-parser can't parse it. See this stackoverflow answer for more information: https://stackoverflow.com/a/38931547/7376526 – Matt Carlotta Jan 09 '20 at 19:34
-1

You need body parser in your node app

 const bodyParser = require('body-parser')

 app.use(
     bodyParser.urlencoded({
         extended: true
     })
 )

app.use(bodyParser.json())

Also, make sure you receive your data. Try logging your data.

tiborK
  • 385
  • 1
  • 6
-1

You need install body-parser, and use this dependency in the app.js (or the name that you using)

Copy the next snippet in the top of the file:

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

Then, copy the next snippet in the file's body;

app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

With this, you route will's done!