Getting request.body undefined in POST requests

Hello everyone,

I’m trying to set up some simple API for my application.
I followed this tutorial with some modifications (I am not using Iron Router).
As of now, the GET request works flawlessly, but the POST is not passing the correct body in the request. Actually, it’s not really passing anything.

I’m using Meteor’s HTTP package to test the calls.

  const data = {
    params: {
      url: "http://www.example.com/"
    }
  };

  HTTP.call("POST", "http://localhost:3000/api/v1/link", data, function(
    error,
    response
  ) {
    if (error) {
      console.log(error);
    } else {
      console.log("Response:", response.message);
    }
  });

I tried changing “params” to “data” as someone suggested, but with no luck.

In my main.js server file I am using WebApp as a middleware,

import { Meteor } from "meteor/meteor";
import { WebApp } from "meteor/webapp";

import { API } from "../imports/api/links";

Meteor.startup(() => {
  WebApp.connectHandlers.use((req, res, next) => {
    res.setHeader("Access-Control-Allow-Origin", "*");
    API.handleRequest(res, req);
  });
});

Here basically doing something like

console.log(req.body);

gives an undefined value.

There’s no need to talk about the API file because req.body is already undefined before being passed to the API file.

Could you help me?

Thank you!

1 Like

You’ll need a middleware to parse the body for you. I recommend the very well used body-parser package

npm install --save body-parser

Then in your main.js:

import bodyParser from 'body-parser';
// For requests with content-type JSON:
WebApp.connectHandlers.use('/path', bodyParser.json());
// For requests with content-type application/x-www-form-urlencoded
WebApp.connectHandlers.use('/path', bodyParser.urlencoded());
// Then your handler:
WebApp.connectHandlers.use((req, res, next) => {
    res.setHeader("Access-Control-Allow-Origin", "*");
    API.handleRequest(res, req);
  });

3 Likes

Thank you, it works!

I am using the same url for both GET and POST requests, so I just pasted the two lines like this:

WebApp.connectHandlers.use("/api/v1/link", bodyParser.json());
  WebApp.connectHandlers.use(
    "/api/v1/link",
    bodyParser.urlencoded({ extended: true })
  );

  WebApp.connectHandlers.use((req, res, next) => {
    const code = req.url.slice(1, 12);

    if (condition) {
      // do something
    } else if (code.toString() === "api/v1/link") {
      res.setHeader("Access-Control-Allow-Origin", "*");
      API.handleRequest(res, req);
    } else {
      next();
    }
  });

Is this approach correct?

Yeah I’m pretty sure it’s fine to do both, as they act on different content types

Guys, thank you both!

Can you explain how does this code work:

WebApp.connectHandlers.use('/path', bodyParser.json()); ?

From what I’ve read about webapp - the second argument to WebApp.connectHandlers.use is built-in function. So how does bodyParser.json() get to work here??

Because if you run bodyParser.json(), the return value of that function call is a function.

2018-11-21 08:58:25 - Freds-MacBook-Pro in ~/development/scratch/body-parser
○ → node
> const bodyParser = require('body-parser')
undefined
> bodyParser.json()
[Function: jsonParser]
>

This allows you to use different parser options for different routes, because all the options will be saved in the returned middleware function that is used for that route.

2 Likes

If you don’t want to use library, you can view this way:


WebApp.connectHandlers.use('/path', (req, res) => {
  req.on('data', Meteor.bindEnvironment((data) => {
    const body = JSON.parse(data);
    // if you use data for return result
    req.end(data);
  }));

  req.on('end', Meteor.bindEnvironment(() => {
    res.setHeader('Content-Type', 'application/json');
    res.writeHead(200);
    res.end(JSON.stringify({ status: 'ok' }));
  }));
});
2 Likes

req.on(‘end’, Meteor.bindEnvironment(() => {

AMAZING – thank you.