fastify-raw-body icon indicating copy to clipboard operation
fastify-raw-body copied to clipboard

I can't get this plugin to work no matter what I do

Open WMcKibbin opened this issue 2 months ago • 2 comments

I have this super simple route to try to get the rawBody logged out in the handler

 server.withTypeProvider<ZodTypeProvider>().route({
        method: 'POST',
        url: '/stripewebhook',
        // config: {
        //   rawBody: true, // enable raw body for this route
        // },
        // preHandler: server.verifyStripeWebhook(),
        handler: async (request, reply) => {
          console.dir(request);
          console.log('----Rawbody------', request.rawBody);

          logger.info(
            request.stripeEvent,
            'Stripe webhook received and verified',
          );
          return reply.code(200).send({ msg: 'webhook received' });
        },
      });
import RawBody from 'fastify-raw-body';
// ...
  await server.register(RawBody, {
    field: 'rawBody',
    global: false,
    encoding: false,
    runFirst: true,
    routes: ['/stripewebhook'],
  });

Fastify Version: "fastify": "^5.2.2",
Raw Body Version: "fastify-raw-body": "^5.0.0",

I've tried the per route settings where you set the config to true, I've tried the above config with the route, I've tried tons of combinations of encoding utf, global true etc etc. I just never get the raw body attached to the request. I know the body is there I see it in the log out of the request. Is the way I define my routes not supported or something? Is the plugin working with later versions of fastify?

WMcKibbin avatar Oct 02 '25 17:10 WMcKibbin

I've ended up just writing my own plugin that basically does the exact same thing as this plugin but as a function decorator on the server. More limited set of functionality as well since I don't need most of the options at were provided by this one. I never figured out why it didn't work.

For those who may stumble across this

Plugin:

import {
  FastifyInstance,
  FastifyPluginAsync,
  preParsingHookHandler,
} from 'fastify';
import fp from 'fastify-plugin';
import getRawBody from 'raw-body';

declare module 'fastify' {
  interface FastifyInstance {
    parseRawBody(): preParsingHookHandler;
  }
  interface FastifyRequest {
    rawBody?: string | Buffer;
  }
}

export type RawBodyPreParserOptions = {};

const rawBodyPreParser: FastifyPluginAsync<RawBodyPreParserOptions> = async (
  fastify: FastifyInstance,
  options: RawBodyPreParserOptions | undefined,
) => {
  fastify.decorate('parseRawBody', function () {
    const handler: preParsingHookHandler = (request, reply, payload, done) => {
      const applyLimit = request.routeOptions.bodyLimit;
      getRawBody(
        payload,
        {
          length: null, // avoid content length check: fastify will do it
          limit: applyLimit, // limit to avoid memory leak or DoS
          encoding: 'utf8',
        },
        function (err, string) {
          if (err) {
            /**
             * the error is managed by fastify server
             * so the request object will not have any
             * `body` parsed.
             *
             * The parseRawBody decorates the request
             * meanwhile the `payload` is processed by
             * the fastify server.
             */
            return;
          }

          request.rawBody = string;
        },
      );

      done(null, payload);
    };

    return handler;
  });
};

const rawBodyPreParserPlugin: FastifyPluginAsync<RawBodyPreParserOptions> = fp(
  rawBodyPreParser,
  {
    name: 'raw-body-pre-parser',
    fastify: '^5.x',
  },
);

export default rawBodyPreParserPlugin;

usage:

server.route({
        method: 'POST',
        url: '/stripewebhook',
        preParsing: [server.parseRawBody()],
        preValidation: server.verifyStripeWebhook(),
        handler: async (request, reply) => {
          request.log.info(
            request.stripeEvent,
            'Stripe webhook received and verified',
          );
          return reply.code(200).send({ msg: 'webhook received' });
        }      
});

The verifyStripeWebhook consumes the request.rawBody that is added and adds the stripeEvent object. If you didn't want to even have a plugin you could just put the handler from the plugin inline or in a utils file or something of that sort.

WMcKibbin avatar Oct 02 '25 19:10 WMcKibbin

Is the plugin registered before the route definition?

Eomm avatar Oct 03 '25 07:10 Eomm