Search code examples
javascriptnode.jsmongodbserverlessnetlify

How do I get the POST data from a netlify serverless function?


Here is the code for my server which works fine. I am trying to achieve this with netlify's serverless functions which I have pasted further below.

CODE ON STANDARD SERVER-HEROKU

const ratingController = {};
const Rating = require("../models/ratingModel");

ratingController.getAllRatings = async function (req, res) {
  const rating = await Rating.find();

  res.status(200).json({
    status: "success",
    data: rating,
  });
};

ratingController.createOneRating = async function (req, res) {
  console.log(req.body);
  req.body.userIp = req.headers["x-forwarded-for"];


  const rating = await Rating.create(req.body);

  // const rating = new Rating(req.body);
  // await rating.save();

  res.status(200).json({
    status: "success",
    data: {
      rating,
    },
  });
};

PART 1 - GET REQUEST

Here's my code for the getAllRatings and it works fine

SERVERLESS FUNCTION - NETLIFY

const { MongoClient } = require("mongodb");
require("dotenv").config();

exports.handler = async function getData(event, context) {
  const client = await MongoClient.connect(process.env.DB, {
    useUnifiedTopology: true,
    useNewUrlParser: true,
  });
  const db = client.db();
  try {
    const slug = event.queryStringParameters.id;
    const data = await db.collection("collectionName").find({ slug }).toArray();
    client.close();

    return {
      statusCode: 200,
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        status: "success",
        data: data,
      }),
    };
  } catch (error) {
    console.log(error);

    return {
      statusCode: 400,
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        status: "fail",
        message: error.message,
      }),
    };
  }
};

My first question for the above is

Just because it works may not mean it's the right way to do it.. I had a few concerns if calling the database each time there's a call is correct and then placing the code the way I have, if it's the way it should be. It's all based on testing and random research. There's no real method being followed so would appreciate some guidance on a more efficient method to do this.

Normally on a regular server the database connection is done just once.. and here I seem to be doing it every time and I am a bit confused if that's ok or not..


PART 2 - POST REQUEST

Here's my code for the POST request createOneRating

SERVERLESS FUNCTION - NETLIFY

const { MongoClient } = require("mongodb");
require("dotenv").config();

exports.handler = async function createRating(event, context) {
  const client = await MongoClient.connect(process.env.DB, {
    useUnifiedTopology: true,
    useNewUrlParser: true,
  });
  const db = client.db();
  try {
    console.log(event);
    const rating = await db.collection("ratings").insertOne(event.body);

    client.close();

    return {
      statusCode: 200,
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        status: "success",
        data: rating,
      }),
    };
  } catch (error) {
    console.log(error);

    return {
      statusCode: 400,
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        status: "fail",
        message: error.message,
      }),
    };
  }
};

This one does not work as it says

{
    "status": "fail",
    "message": "Cannot create property '_id' on string ''"
}

And I guess that's because event.body is not where the data is.. but I am not sure how to get the POST data in a serverless deployment.

So my second question is

How do I retrieve the data sent by a POST request. As there's no request parameter I am a bit confused.

Also I'd like to add the IP of the user so other than the POST data I'd also need some help on how to do this

  req.body.userIp = req.headers["x-forwarded-for"];


Solution

  • Based on my own research, I have answers to the questions and am placing them here for my own reference and for those who might face a similar situation in the future.

    Question 1 : Is it ok to make a database connection on every call that's made to a serverless function

    It seems it's ok to do this and for those, like me, who thought that maybe it was not the right way to do it, it's definitely not the wrong way. Maybe there's an efficient way to do this and I'd be open to learn more about this if possible. But for now, it's good to know that it's not wrong to connect to the database each time you make a call.

    Question 2: How to make a POST request on a serverless as there's no request parameter

    I was not aware that the event parameter is in fact a replacement for the request parameter and that the headers and body are properties of the event object and can be accessed in the same way ie event.body and event.headers. Here's a link that could save you some time to confirm this.

    (https://docs.netlify.com/functions/build-with-javascript/#synchronous-function-format)

    And if you, like me, don't know if a serverless function can be defined as GET or POST or run into an issue where the POST request gets converted into a GET when making a function call here's a link that would help.

    How to define Netlify function endpoint as POST?