ゆずめも

メモ的なブログです。主に勉強した事について書いてます。

nestjsでpostのraw bodyを取得する方法

webhookのverificationでbodyParseされてないraw bodyが必要になって割と困ったのでメモ

tl;dr

結局方法3で実装した

ダメだったやり方

検索すると一番最初に以下のstack overflowが引っかかって、raw-bodyというnpmモジュールをインストールしてrawbodyを渡すデコレータ作って簡単にできるのかと思ったが、実際に動かしてみるとif(req.readable)が常にfalseになっていてうまく動作しなかった

stackoverflow.com

方法1

別のstack overflowの質問*1で見つけたやり方

nest.jsが内部で設定しているbodyParserを無効化して、Requestを拡張してrawBodyプロパティを作り、手動でbodyParserを有効にする。

自分の用途だとwebhookの時だけrawが欲しいだけなのに、毎回rawを生成するのはちょっと違和感があるけど動いた

const app = await NestFactory.create(AppModule, {
  bodyParser: false
});

const rawBodyBuffer = (req: http.IncomingMessage, res: http.ServerResponse, buf: Buffer, encoding: string) => {
  if (buf && buf.length) {
    // ここうまく型を解決する方法がわからなかった
    (req as any).rawBody = buf.toString((encoding || 'utf8') as BufferEncoding);
  }
};

app.use(bodyParser.urlencoded({verify: rawBodyBuffer, extended: true }));
app.use(bodyParser.json({ verify: rawBodyBuffer }));

方法2

いまいちnest.jsの挙動を理解してなくて、方法3の方が簡単だったので実際には試してない。
jsonパース用のmiddlewareとbodyをrawで提供するmiddlewareを作成して、app.module.tsで設定するやり方

stackoverflow.com

AppModuleというかNestModuleにはconfigureという関数があって、apply, forRoutesを組み合わせて特定のmiddlewareを適用することができるの初めて知った

docs.nestjs.com

方法3

シンプルにapp.useを使うやり方
簡単だったし、どこかで特定のパスを指定しないといけないならmain.tsで指定してやるのが大体の設定が書かれているのでいい気がした

 app.use('/webhook', express.raw({type: 'application/json'}));

終わりに

記事に直接関係無いけど、今回調べててexpressにbody-parserが入ってわざわざ別でbody-parserインストールする必要がなくなってたことを知った