0

I recently added express-static-gzip to my server and have since noticed that my req.body is undefined in my router.post when submitting a form.

Previously it was working without issue but now I am getting a POST 500 internal server error, a Cannot read property "name" of undefined & a Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0 error.

here is my form submission:

const handleSubmit = async (e) => {
    
    e.preventDefault();
    setStatus("Sending...");
    const { name, email, message } = e.target.elements;
    let details = {
        name: name.value,
        email: email.value,
        message: message.value,
    };
    console.log(typeof JSON.stringify(details))
    let response = await fetch("/api/v1/mail", {
        method: "POST",
        headers: {
            "Content-Type": "application/json;charset=utf-8"
        },
        body: JSON.stringify(details),
    });
    setStatus("Send Message");
    let result = await response.json();
    alert(result.status);
};

here is my server setup, the route in question is '/api/v1/mail':

const express = require('express')
const path = require('path')
const router = express.Router();
const cors = require("cors");

var expressStaticGzip = require("express-static-gzip")

const mailRoutes = require('./routes/mail');

const server = express()

server.use('/api/v1/mail', mailRoutes)
server.use(cors())
server.use(express.json())
server.use("/", router)
server.use(expressStaticGzip(path.join(__dirname, 'public'), {
  enableBrotli: true
}))

server.use(express.static(path.join(__dirname, 'public')))

and here is my POST request:

       router.post("/", (req, res) => {
  const name = req.body.name;
  const email = req.body.email;
  const orderId = req.body.orderId
  const message = req.body.message; 
  const mail = {
    from: name,
    to: "info@example.com ",
    subject: "Contact Form Submission",
    html: `<p>Name: ${name}</p>
           <p>Email: ${email}</p>
           <p>Order ID: ${orderId}
           <p>Message: ${message}</p>`,
  };
  contactEmail.sendMail(mail, (error) => {
    if (error) {
      res.json({ status: "ERROR" , req});
    } else {
      res.json({ status: "Message Sent" });
    }
  });
});

})
DuckSoup
  • 91
  • 5
  • What is the content-type when you submit your form? – jfriend00 May 09 '21 at 03:34
  • Which router is the problem one: `server.use('/api/v1/mail', mailRoutes)` or `server.use("/", router)`? – jfriend00 May 09 '21 at 03:43
  • Why did you post and disappear? We're trying to help you, but you're gone so you can't clear up the things that are unclear. This is not how you should be using Stackoverflow. Don't post and disappear. Hang around for at least the next 30-45 minutes, checking back several times to see if people have clarifying questions. Only post when you can hang around and check back numerous times. This is how you engage with the people that try to help. People rarely ask perfect questions - so we often need help understanding your problem. If you're gone, then you just lose your chance for help. – jfriend00 May 09 '21 at 08:02
  • Hi, very sorry for not replying sooner, wont happen again! I have edited the post with more details on the form submission an POST request, which highlight content type and specific router respectively. Thanks – DuckSoup May 09 '21 at 20:52
  • OK, it looks like a middleware ordering issue - see my answer below. – jfriend00 May 09 '21 at 21:05

1 Answers1

0

If the route you're trying to use req.body.name in is this one:

server.use('/api/v1/mail', mailRoutes)

Then, you have to move this:

server.use(express.json())

to be BEFORE that route definition.

As it is, you're trying to handle the route request before your middleware has read and parsed the JSON. Route handlers and middleware are matched and executed in the order they are registered. So, any middleware that needs to execute for a route handler to function must be registered before the route handler itself is registered.

jfriend00
  • 683,504
  • 96
  • 985
  • 979