question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

@golevel/nestjs-webhooks `RawBodyMiddleware` and `JsonBodyMiddleware` incompatible with @nestjs/platform-fastify

See original GitHub issue

The middlewares use the Express req and res objects.

I spent a good amount of time trying to figure this one out last night, because Stripe explodes on you if the webhook payload format isn’t exactly how it wants =/

https://github.com/fastify/help/issues/158 https://github.com/fastify/fastify/issues/1965

According to this thread, you can set this up in Fastify like this:

 fastify.addContentTypeParser(
    'application/json',
    { parseAs: 'buffer' },
    function (req, body, done) {
      try {
        var newBody = {
          raw: body
        }
        done(null, newBody)
      } catch (error) {
        error.statusCode = 400
        done(error, undefined)
      }
    }
  )

  fastify.post('/stripe/myhook', {
    handler: async (req, res) => {
      const sig = req.headers['stripe-signature']
      const webhookSecret = 'whsec_d....'

      const event = stripe.webhooks.constructEvent(req.body.raw, sig, webhookSecret)
      .....
    }
  })

So I attempted this in a hacky way and still no luck. It seems setting req.body, req.rawBody, and req.raw does not work. And this is a poor implementation anyways because it’s global.

If anyone has figured this out, would be great info + maybe I can PR a second set of middlewares that support @nestjs/platform-fastify.

import { AppModule } from './app.module'
import { NestFactory } from '@nestjs/core'
import {
  FastifyAdapter,
  NestFastifyApplication,
} from '@nestjs/platform-fastify'
import fastify from 'fastify'

async function bootstrap() {
  const fastifyInstance = fastify()
  fastifyInstance.addContentTypeParser(
    'application/json',
    { parseAs: 'buffer' },
    function (req, body, done) {
      try {
        console.log('Parsing req with body:', body)
        var newBody = {
          body,
          rawBody: body,
          raw: body
        }
        console.log('Parsed body result:', newBody)
        done(null, newBody)
      } catch (error) {
        error.statusCode = 400
        done(error, undefined)
      }
    }
  )

  const app = await NestFactory.create<NestFastifyApplication>(
    AppModule,
    new FastifyAdapter(fastifyInstance as any), {
    // Disable body parsing for Stripe webhooks to work properly. Needs raw request body.
    bodyParser: false,
  })

  await app.listen(3001, '0.0.0.0')
}

bootstrap()

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:1
  • Comments:8 (2 by maintainers)

github_iconTop GitHub Comments

5reactions
pintobikezcommented, Mar 3, 2021

I solved it using fastify-raw-body

main.ts

import rawBody from 'fastify-raw-body';

async function bootstrap() {
......
       //enable rawBody
	app.register(rawBody, {
		field: 'rawBody', // change the default request.rawBody property name
		global: true, // add the rawBody to every request. **Default true**
		encoding: false,
		runFirst: true, // get the body before any preParsing hook change/uncompress it. **Default false**
	});
}
3reactions
fasenderoscommented, Sep 5, 2021

That’s how I managed to enable this plugin only on one route:

## main.ts
...
import rawBody from 'fastify-raw-body';
import fastify from 'fastify';
const fastifyInstance = fastify();
fastifyInstance.addHook('onRoute', (opts) => {
  if (opts.path === '/webhook/subscription') {
    opts.config = { rawBody: true };
  }
});

async function bootstrap() {
  const fastify = new FastifyAdapter(fastifyInstance);
  const app = await NestFactory.create<NestFastifyApplication>(
    AppModule,
    fastify,
  );
  ...
  ...
  await app.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**
  });

  // Start server
  await app.listen(port, ip);
}
bootstrap();
Read more comments on GitHub >

github_iconTop Results From Across the Web

No results found

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found