少し前に Fastify の 4 が出たってニュースを見かけて簡単な変更点紹介で ルートのハンドラー内でのレスポンスの返し方が統一されたみたいのを聞いてました
Fastify のルートハンドラーではコールバック関数と async 関数どっちでも使えるようになってることもあって 以前使ったときは罠のような仕様があって不便に感じたので あれが改善されたんだなーと思ってました

一般的なレスポンスの返し方はこの 2 パターンです

fastify.get("/foo", (request, reply) => {
reply.send({ hello: "world" })
})

fastify.get("/bar", async (request, reply) => {
return { hello: "world" }
})

通常の関数ならコールバック関数で async 関数なら return でレスポンスを返します
async 関数でできるならと通常の関数でも return でレスポンスを返したくなります
しかしこれは無視されるようで reply を使ったコールバック関数を呼び出さないとレスポンスは返されずブラウザはずっとロード中になります
他フレームワークだとだいたいデフォルトのレスポンスを返してくれて Node.js を生で使ったときみたいにレスポンスを返さず放置はなかったのでこれが Fastify の不満点の一つでした

return 値をレスポンスとして捉えてしまうとあとから reply 関数を呼び出す場合に対応できなくなるので return は無視する仕組みなんだと理解しましたが それでも async 関数の場合は return できるので使いづらく感じます
それがあってから全部 async 関数にしようとしてますが それでも async 関数になってなかったということはけっこうあります

そういう問題があって きっと 4 での変更点はこれが改善されたんだろうなと思って試してみました

fastify.get("/", (request, reply) => {
return { hello: "world" }
})

でレスポンスが返ってきました
改善されてるーと喜んで記事にでも書こうかと思って ついでに 4 の変更点をまとめた公式ブログの発表を軽く見ていると……これのことじゃなさそう
async 関数のときに あとからコールバック関数を使うなら reply を return しないといけないとか書いてる

じゃあもっと前から直ってたの?
と思って 3 系をいくつか試したところ どれも return でレスポンスを返せていました
そんな前から対応されてたんだ
まぁ あとから reply を呼び出すつもりなら return が undefined になりそうだし 十分判断はできるのかな
やっぱり気になったので Github で履歴見てみると 3.0 の更新で変更されてました

その他の 4 での変更点はあまり興味ない部分でしたし 今回はメジャーアップデートの割にそんなに大きく変わってないようです