mikemaccana
mikemaccana

Reputation: 123410

How do I access the raw body of a Fastify request?

As you may imagine, I'm familiar with Express, but this is the first time I'm using Fastify.

I'd like to access the unmodified body of a Fastify request, for signature verification of a webhook - ie, I would like to see the request as it came in, unmodified by any middleware. In Express this is often done by accessing request.rawBody.

How do I access the raw body of a Fastify request?

Upvotes: 5

Views: 28519

Answers (4)

Aiman Farhan
Aiman Farhan

Reputation: 216

According to the docs https://docs.nestjs.com/faq/raw-body

in main.ts

  const app = await NestFactory.create<NestFastifyApplication>(
    AppModule,
    new FastifyAdapter(),
    {
      rawBody: true,
    },
  );

Then in your controller

  async handleStripeEvent(
    @Headers('stripe-signature') signature: string,
    @Req() request: RawBodyRequest<FastifyRequest>,
  ) {
    if (!signature) {
      throw new BadRequestException('Missing stripe-signature header');
    }

    const event = await this.webhooksService.handleStripePaymentWebhook(
      signature,
      request.rawBody,
    );
  }

Upvotes: 4

fatihpense
fatihpense

Reputation: 653

You can also check this community plugin: https://github.com/Eomm/fastify-raw-body

If you are using Typescript & fastify/autoload, place this to plugins/rawbody.ts:

import fp from "fastify-plugin";

import rawbody, { RawBodyPluginOptions } from "fastify-raw-body";

export default fp<RawBodyPluginOptions>(async (fastify) => {
  fastify.register(rawbody, {
    field: "rawBody", // change the default request.rawBody property name
    global: false, // add the rawBody to every request. **Default true**
    encoding: "utf8", // set it to false to set rawBody as a Buffer **Default utf8**
    runFirst: true, // get the body before any preParsing hook change/uncompress it. **Default false**
    routes: [], // array of routes, **`global`** will be ignored, wildcard routes not supported
  });
});

Since global:false We need to configure it in the specific handler:

  fastify.post<{ Body: any }>(
    "/api/stripe_webhook",
    {
      config: {
        // add the rawBody to this route. if false, rawBody will be disabled when global is true
        rawBody: true,
      },
    },

    async function (request, reply) {
...

Then you can access raw body in the handler using request.rawBody

Upvotes: 9

mikemaccana
mikemaccana

Reputation: 123410

Note: Fastify requests can only have req.body - they can't have, for example, req.body and req.rawBody like other web servers (for example, Express). This is because addContentTypeParser() only returns a modified body, it can't add anything else to the request.

Instead, in a content type parser we only add to one route, we make:

  • req.body.parsed (the object, same content that would normally be in req.body)
  • req.body.raw (the string)

See GitHub and the addContentTypeParser() docs for more.

  server.addContentTypeParser(
    "application/json",
    { parseAs: "string" },
    function (req, body, done) {
      try {
        var newBody = {
          raw: body,
          parsed: JSON.parse(body),
        };
        done(null, newBody);
      } catch (error) {
        error.statusCode = 400;
        done(error, undefined);
      }
    }
  );

Upvotes: 4

lambda
lambda

Reputation: 417

There's an issue on GitHub for rawBody support

And there's a module too: "raw-body". To use this module in Fastify:

const rawBody = require('raw-body')

fastify.addContentTypeParser('*', (req, done) => {
    rawBody(req, {
        length: req.headers['content-length'],
        limit: '1mb',
        encoding: 'utf8', // Remove if you want a buffer
    }, (err, body) => {
        if (err) return done(err)
        done(null, parse(body))
    })
})

I hope that I helped you, I'm new on fastify too

Upvotes: 2

Related Questions