Mike
Mike

Reputation: 24393

JSON not being parsed for validation when doing a POST request to Fastify

In my routes, I have the following:

const reservationSchema = {
  body: {
    type: 'object',
    required: ['in', 'out', 'guests', 'language', 'roomsSelected'],
    properties: {
      language: {
        type: 'string',
      },
      // ... several other property validations here
    }
  }
};

fastify.post(
  '/api/reservations/:slug',
  { schema: reservationSchema },
  reservationsController.addReservation
);

I send the POST request from React like this:

const response = await fetch(process.env.REACT_APP_API_HOSTNAME + '/api/reservations/' + property.slug, {
  method: 'POST',
  body: JSON.stringify(requestBody)
});

I can see that it is correctly sending JSON when I look at the request:

screenshot

However I receive the following response:

{
  "statusCode":400,
  "error":"Bad Request",
  "message":"body should be object"
}

Am I missing something to automatically parse the POST body as an object in Fastify so I can validate it using a validation schema? Even in my reservationsController.addReservation() function I need to manually do JSON.parse() on req.body.

Upvotes: 3

Views: 2716

Answers (1)

Mike
Mike

Reputation: 24393

From the fetch() docs:

Both request and response (and by extension the fetch() function), will try to intelligently determine the content type. A request will also automatically set a Content-Type header if none is set in the dictionary.

However, (at least in Chrome), when you send a JSON string, it does not intelligently determine that this string is JSON, and instead sends the Content-Type header as text/plain;charset=UTF-8. Since the server receives this Content-Type header, it assumes that you are sending a plan text string and therefore does not parse it as JSON.

To make the server automatically parse the body as JSON, you need to make sure to set the Content-Type header to application/json. Like this:

const response = await fetch(process.env.REACT_APP_API_HOSTNAME + '/api/reservations/' + property.slug, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(requestBody)
});

Upvotes: 8

Related Questions