Search code examples
node.jsfetch-apiform-databody-parser

Trying to send form data to Express app, can't parse into req.body correctly


I know that a similar question has been asked many times, e.g. here.

However, I've tried applying various solutions from these answers without success.

Here's my client-side page:

<form id="submit_newuser" method="POST" action="/submit_newuser">
    User name:
    <input type="text" id="username" name="username" />
    <br>
    Phone number:
    <input type="text" id="phonenumber" name="phonenumber" />
    <br><br>
    <input type="submit" />
</form>

<script>
document.getElementById("submit_newuser").addEventListener('submit',submit_newuser);

function submit_newuser(event){
    event.preventDefault();
    submit_newuserForm=document.getElementById("submit_newuser");
    formData=new FormData(submit_newuserForm);
    fetch("/submit_newuser",{
        body:formData,
        headers:{
            "Content-Type": "application/json"
        },
        method:"post"
    })
    .then(response=>console.log(response))
    .catch(err=>"submit_newuser: error: "+err);
}
</script>

And here's the relevant server-side code for the /submit_newuser endpoint:

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

app.post('/submit_newuser',function(req,res){
    console.log("/submit_newuser: req.body: "+JSON.stringify(req.body));
    var phonenumber=req.body.phonenumber;
    var username=req.body.username;
    var output="you submitted: "+username+" "+phonenumber;
    console.log("/submit_newuser: text to send back: "+output);
    res.send(output);
});

With this, when I submit data from the page, the server logs this error:

SyntaxError: Unexpected token - in JSON at position 0

When I change the Content-Type to "application/x-www-form-urlencoded", I get this console logging:

/submit_newuser: req.body: {"------WebKitFormBoundaryBDU4OcntAv7d5wWL\r\nContent-Disposition: form-data; name":"\"username\"\r\n\r\ntestUserName\r\n------WebKitFormBoundaryBDU4OcntAv7d5wWL\r\nContent-Disposition: form-data; name=\"phonenumber\"\r\n\r\ntestPhoneNumber\r\n------WebKitFormBoundaryBDU4OcntAv7d5wWL--\r\n"}

/submit_newuser: text to send back: you submitted: undefined undefined

Which indicates that the data is being posted to the server, but not properly parsed into req.body.

Solutions involving multer don't seem to apply here because I'm not uploading a file, but I'm not sure if I should nonetheless be using a different approach than posting a FormData object in the fetch() body.

I'm confused, and also wondering if there's a simpler way to do this. I just want to post form data to the server without triggering a page refresh, and be able to update page elements with the server response.


Solution

  • You can update your client-side code to send a JSON body like so, this will be parsed correctly by the server.

    Because we're setting the content-type header to JSON on the client, we must send JSON data. We could send url encoded data or multipart/form-data, however we would have to change headers on the client to do this.

    document.getElementById("submit_newuser").addEventListener('submit',submit_newuser);
    
    function formDataToJson(formData) {
        const obj = {};
        formData.forEach((value, key) => { 
            obj[key] = value
        });
        return JSON.stringify(obj);
    }
    
    function submit_newuser(event){
        event.preventDefault();
        submit_newuserForm=document.getElementById("submit_newuser");
        formData = new FormData(submit_newuserForm);
        fetch("/submit_newuser",{
            body: formDataToJson(formData),
            headers: {
                "Content-Type": "application/json"
            },
            method:"post"
        })
        .then(response=>console.log(response))
        .catch(err=>"submit_newuser: error: "+err);
    }