nestjsでpostのraw bodyを取得する方法
webhookのverificationでbodyParseされてないraw bodyが必要になって割と困ったのでメモ
tl;dr
結局方法3で実装した
ダメだったやり方
検索すると一番最初に以下のstack overflowが引っかかって、raw-body
というnpmモジュールをインストールしてrawbodyを渡すデコレータ作って簡単にできるのかと思ったが、実際に動かしてみるとif(req.readable)
が常にfalse
になっていてうまく動作しなかった
方法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
で設定するやり方
AppModule
というかNestModule
にはconfigure
という関数があって、apply
, forRoutes
を組み合わせて特定のmiddlewareを適用することができるの初めて知った
方法3
シンプルにapp.useを使うやり方
簡単だったし、どこかで特定のパスを指定しないといけないならmain.ts
で指定してやるのが大体の設定が書かれているのでいい気がした
app.use('/webhook', express.raw({type: 'application/json'}));
終わりに
記事に直接関係無いけど、今回調べててexpressにbody-parserが入ってわざわざ別でbody-parserインストールする必要がなくなってたことを知った
夜中に思ってたのこういう事だったのか
— ゆず🍜 (@yuzu_441) 2020年8月26日
Body-ParserがExpressにexpress.json()として標準搭載されている話 https://t.co/vs370imhEX #Qiita