V5移行ガイド
このガイドは、Fastify v4からv5への移行を支援することを目的としています。
v5に移行する前に、v4からのすべての非推奨警告を修正していることを確認してください。すべてのv4の非推奨機能は削除されており、アップグレード後は機能しなくなります。
長期サポートサイクル
Fastify v5はNode.js v20以降のみサポートします。古いバージョンのNode.jsを使用している場合は、Fastify v5を使用するには新しいバージョンにアップグレードする必要があります。
Fastify v4は2025年6月30日までサポートされます。アップグレードできない場合は、HeroDevsから製品寿命終了後のサポートプランを購入することを検討してください。
Node.js v20の理由
Fastify v5は、`node:test`の優れたサポートなど、v18と比較して大きな違いがあるため、Node.js v20以降のみサポートします。これにより、より優れた開発者エクスペリエンスを提供し、メンテナンスを合理化できます。
Node.js v18は2025年4月30日に長期サポートを終了するため、いずれにしてもv20へのアップグレードを計画する必要があります。
破壊的変更
完全なJSONスキーマは、`querystring`、`params`、`body`、およびレスポンススキーマで必須になりました
v5以降、Fastifyは`querystring`、`params`、`body`スキーマに完全なJSONスキーマを要求します。`jsonShortHand`オプションも削除されたことに注意してください。
デフォルトのJSONスキーマバリデーターを使用する場合は、`type`プロパティを含む`querystring`、`params`、`body`、`response`スキーマに完全なJSONスキーマを提供する必要があります。
// v4
fastify.get('/route', {
schema: {
querystring: {
name: { type: 'string' }
}
}
}, (req, reply) => {
reply.send({ hello: req.query.name });
});
// v5
fastify.get('/route', {
schema: {
querystring: {
type: 'object',
properties: {
name: { type: 'string' }
},
required: ['name']
}
}
}, (req, reply) => {
reply.send({ hello: req.query.name });
});
詳細については、#5586を参照してください。
Zodなどの異なる形式を使用するためにJSONスキーマバリデーターをオーバーライドすることは依然として可能です。この変更は、それを簡素化します。
この変更は、@fastify/swagger
などの他のツールとの統合に役立ちます。
新しいロガーコンストラクターシグネチャ
Fastify v4では、`logger`オプションにpinoロガーを構築するためのオプションと、カスタムロガーインスタンスを受け入れていました。これは大きな混乱の原因となっていました。
その結果、v5では`logger`オプションはカスタムロガーを受け入れなくなりました。カスタムロガーを使用するには、代わりに`loggerInstance`オプションを使用してください。
// v4
const logger = require('pino')();
const fastify = require('fastify')({
logger
});
// v5
const loggerInstance = require('pino')();
const fastify = require('fastify')({
loggerInstance
});
`useSemicolonDelimiter`はデフォルトでfalse
v5以降、Fastifyインスタンスは、v4で行っていたように、クエリ文字列でのセミコロン区切り記号の使用をデフォルトでサポートしなくなりました。これは、標準外の動作であり、RFC 3986に準拠していないためです。
それでもセミコロンを区切り記号として使用したい場合は、サーバー設定で`useSemicolonDelimiter: true`を設定できます。
const fastify = require('fastify')({
useSemicolonDelimiter: true
});
パラメーターオブジェクトにはプロトタイプがなくなりました
v4では、`parameters`オブジェクトにプロトタイプがありました。v5では、これはもう当てはまりません。つまり、`toString`や`hasOwnProperty`など、`Object`から継承されたプロパティを`parameters`オブジェクトでアクセスできなくなりました。
// v4
fastify.get('/route/:name', (req, reply) => {
console.log(req.params.hasOwnProperty('name')); // true
return { hello: req.params.name };
});
// v5
fastify.get('/route/:name', (req, reply) => {
console.log(Object.hasOwn(req.params, 'name')); // true
return { hello: req.params.name };
});
これにより、プロトタイプ汚染攻撃に対する防御を強化することで、アプリケーションのセキュリティが向上します。
タイププロバイダーは、バリデーターとシリアライザーのスキーマを区別するようになりました
v4では、タイププロバイダーは検証とシリアライゼーションの両方に同じ型を持っていました。v5では、タイププロバイダーは`ValidatorSchema`と`SerializerSchema`という2つの別々の型に分割されています。
@fastify/type-provider-json-schema-to-ts
と@fastify/type-provider-typebox
はすでに更新されています。新しい型を取得するには、最新バージョンにアップグレードしてください。カスタムタイププロバイダーを使用している場合は、次のように変更する必要があります。
--- a/index.ts
+++ b/index.ts
@@ -11,7 +11,8 @@ import {
import { FromSchema, FromSchemaDefaultOptions, FromSchemaOptions, JSONSchema } from 'json-schema-to-ts'
export interface JsonSchemaToTsProvider<
Options extends FromSchemaOptions = FromSchemaDefaultOptions
> extends FastifyTypeProvider {
- output: this['input'] extends JSONSchema ? FromSchema<this['input'], Options> : unknown;
+ validator: this['schema'] extends JSONSchema ? FromSchema<this['schema'], Options> : unknown;
+ serializer: this['schema'] extends JSONSchema ? FromSchema<this['schema'], Options> : unknown;
}
.listen()メソッドの変更
.listen()メソッドの可変長引数シグネチャは削除されました。つまり、可変数の引数で`.listen()`を呼び出すことができなくなりました。
// v4
fastify.listen(8000)
こうなります
// v5
fastify.listen({ port: 8000 })
これはv4で`FSTDEP011`として既に非推奨になっていたので、新しいシグネチャを使用するようにコードを既に更新しているはずです。
トレーラーの直接返却が削除されました
v4では、ハンドラーからトレーラーを直接返すことができました。v5では、これはできなくなりました。
// v4
fastify.get('/route', (req, reply) => {
reply.trailer('ETag', function (reply, payload) {
return 'custom-etag'
})
reply.send('')
});
// v5
fastify.get('/route', (req, reply) => {
reply.trailer('ETag', async function (reply, payload) {
return 'custom-etag'
})
reply.send('')
});
コールバックを使用することもできました。これはv4で`FSTDEP013`として既に非推奨になっていたので、新しいシグネチャを使用するようにコードを既に更新しているはずです。
ルート定義へのアクセスが簡素化されました
ルート定義へのアクセスに関するすべての非推奨プロパティが削除され、現在は`request.routeOptions`からアクセスされます。
コード | 説明 | 解決方法 | 議論 |
---|---|---|---|
FSTDEP012 | 非推奨の`request.context`プロパティにアクセスしようとしています。 | `request.routeOptions.config`または`request.routeOptions.schema`を使用してください。 | #4216 #5084 |
FSTDEP015 | 非推奨の`request.routeSchema`プロパティにアクセスしています。 | `request.routeOptions.schema`を使用してください。 | #4470 |
FSTDEP016 | 非推奨の`request.routeConfig`プロパティにアクセスしています。 | `request.routeOptions.config`を使用してください。 | #4470 |
FSTDEP017 | 非推奨の`request.routerPath`プロパティにアクセスしています。 | `request.routeOptions.url`を使用してください。 | #4470 |
FSTDEP018 | 非推奨の`request.routerMethod`プロパティにアクセスしています。 | `request.routeOptions.method`を使用してください。 | #4470 |
FSTDEP019 | 非推奨の`reply.context`プロパティにアクセスしています。 | `reply.routeOptions.config`または`reply.routeOptions.schema`を使用してください。 | #5032 #5084 |
詳細については、#5616を参照してください。
`reply.redirect()`の新しいシグネチャ
`reply.redirect()`メソッドの新しいシグネチャは次のとおりです。`reply.redirect(url: string, code?: number)`。
// v4
reply.redirect(301, '/new-route')
次のように変更してください。
// v5
reply.redirect('/new-route', 301)
これはv4で`FSTDEP021`として既に非推奨になっていたので、新しいシグネチャを使用するようにコードを既に更新しているはずです。
`reply.sent`の変更は禁止されました
v4では、`reply.sent`プロパティを変更してレスポンスの送信を防ぐことができました。v5では、これはできなくなりました。代わりに`reply.hijack()`を使用してください。
// v4
fastify.get('/route', (req, reply) => {
reply.sent = true;
reply.raw.end('hello');
});
次のように変更してください。
// v5
fastify.get('/route', (req, reply) => {
reply.hijack();
reply.raw.end('hello');
});
これはv4で`FSTDEP010`として既に非推奨になっていたので、新しいシグネチャを使用するようにコードを既に更新しているはずです。
ルートバージョニングシグネチャ変更の制約
ルートバージョニングの制約のシグネチャを変更しました。`version`オプションと`versioning`オプションは削除され、代わりに`constraints`オプションを使用する必要があります。
コード | 説明 | 解決方法 | 議論 |
---|---|---|---|
FSTDEP008 | ルートの`{version: "..."}`オプションを使用してルート制約を使用しています。 | `{constraints: {version: "..."}}`オプションを使用してください。 | #2682 |
FSTDEP009 | サーバーの{versioning: "..."} オプションを使用して、カスタムルートバージョン管理戦略を使用しています。 | `{constraints: {version: "..."}}`オプションを使用してください。 | #2682 |
exposeHeadRoutes: true
の場合、GET
の前にHEAD
ルートを登録する必要があります
exposeHeadRoutes: true
の場合、カスタムHEAD
ルートにさらに厳格な要件があります。
カスタムHEAD
ルートを提供する場合、exposeHeadRoutes
を明示的にfalse
に設定するか、
// v4
fastify.get('/route', {
}, (req, reply) => {
reply.send({ hello: 'world' });
});
fastify.head('/route', (req, reply) => {
// ...
});
// v5
fastify.get('/route', {
exposeHeadRoutes: false
}, (req, reply) => {
reply.send({ hello: 'world' });
});
fastify.head('/route', (req, reply) => {
// ...
});
HEAD
ルートをGET
の前に配置する必要があります。
// v5
fastify.head('/route', (req, reply) => {
// ...
});
fastify.get('/route', {
}, (req, reply) => {
reply.send({ hello: 'world' });
});
これは#2700で変更され、旧動作はv4でFSTDEP007
として非推奨になりました。
request.connection
の削除
request.connection
プロパティはv5で削除されました。代わりにrequest.socket
を使用してください。
// v4
fastify.get('/route', (req, reply) => {
console.log(req.connection.remoteAddress);
return { hello: 'world' };
});
// v5
fastify.get('/route', (req, reply) => {
console.log(req.socket.remoteAddress);
return { hello: 'world' };
});
これはv4でFSTDEP05
として既に非推奨になっていたため、新しいシグネチャを使用するようにコードを既に更新しているはずです。
reply.getResponseTime()
は削除されました。代わりにreply.elapsedTime
を使用してください
reply.getResponseTime()
メソッドはv5で削除されました。代わりにreply.elapsedTime
を使用してください。
// v4
fastify.get('/route', (req, reply) => {
console.log(reply.getResponseTime());
return { hello: 'world' };
});
// v5
fastify.get('/route', (req, reply) => {
console.log(reply.elapsedTime);
return { hello: 'world' };
});
これはv4でFSTDEP20
として既に非推奨になっていたため、新しいシグネチャを使用するようにコードを既に更新しているはずです。
fastify.hasRoute()
はfind-my-way
の動作に一致するようになりました
fastify.hasRoute()
メソッドは、find-my-way
の動作に一致するようになり、ルート定義をルートで定義されているとおりに渡す必要があります。
// v4
fastify.get('/example/:file(^\\d+).png', function (request, reply) { })
console.log(fastify.hasRoute({
method: 'GET',
url: '/example/12345.png'
)); // true
// v5
fastify.get('/example/:file(^\\d+).png', function (request, reply) { })
console.log(fastify.hasRoute({
method: 'GET',
url: '/example/:file(^\\d+).png'
)); // true
一部の非標準HTTPメソッドの削除
Fastifyから以下のHTTPメソッドを削除しました。
PROPFIND
PROPPATCH
MKCOL
COPY
MOVE
LOCK
UNLOCK
TRACE
SEARCH
acceptHTTPMethod
メソッドを使用して、これらを再び追加できるようになりました。
const fastify = Fastify()
// add a new http method on top of the default ones:
fastify.acceptHTTPMethod('REBIND')
// add a new HTTP method that accepts a body:
fastify.acceptHTTPMethod('REBIND', { hasBody: true })
// reads the HTTP methods list:
fastify.supportedMethods // returns a string array
詳細については、#5567を参照してください。
デコレータでの参照型のサポート削除
この参照はすべてのリクエスト間で共有されるため、参照型(Array
、Object
)を使用してRequest/Replyをデコレートすることは禁止されています。
// v4
fastify.decorateRequest('myObject', { hello: 'world' });
// v5
fastify.decorateRequest('myObject');
fastify.addHook('onRequest', async (req, reply) => {
req.myObject = { hello: 'world' };
});
または、関数の形式にする
// v5
fastify.decorateRequest('myObject', () => { hello: 'world' });
または、ゲッターとして
// v5
fastify.decorateRequest('myObject', {
getter () {
return { hello: 'world' }
}
});
詳細については、#5462を参照してください。
Content-Type: application/json
ヘッダーと空のボディを持つDELETEのサポート削除
v4では、FastifyはContent-Type: application/json
ヘッダーと空のボディを持つDELETE
リクエストを受け入れていました。v5では、これは許可されなくなりました。
詳細については、#5419を参照してください。
プラグインは、コールバック/Promise APIを混合できなくなりました
v4では、プラグインはコールバックとPromise APIを混合することができ、予期しない動作につながることがありました。v5では、これは許可されなくなりました。
// v4
fastify.register(async function (instance, opts, done) {
done();
});
// v5
fastify.register(async function (instance, opts) {
return;
});
または
// v5
fastify.register(function (instance, opts, done) {
done();
});
getDefaultRoute
メソッドとsetDefaultRoute
メソッドの削除
getDefaultRoute
メソッドとsetDefaultRoute
メソッドはv5で削除されました。
詳細については、#4485と#4480を参照してください。これはv4でFSTDEP014
として既に非推奨になっていたため、コードを既に更新しているはずです。
新機能
診断チャネルのサポート
Fastify v5は、診断チャネルAPIをネイティブにサポートし、リクエストのライフサイクルを追跡する方法を提供します。
'use strict'
const diagnostics = require('node:diagnostics_channel')
const sget = require('simple-get').concat
const Fastify = require('fastify')
diagnostics.subscribe('tracing:fastify.request.handler:start', (msg) => {
console.log(msg.route.url) // '/:id'
console.log(msg.route.method) // 'GET'
})
diagnostics.subscribe('tracing:fastify.request.handler:end', (msg) => {
// msg is the same as the one emitted by the 'tracing:fastify.request.handler:start' channel
console.log(msg)
})
diagnostics.subscribe('tracing:fastify.request.handler:error', (msg) => {
// in case of error
})
const fastify = Fastify()
fastify.route({
method: 'GET',
url: '/:id',
handler: function (req, reply) {
return { hello: 'world' }
}
})
fastify.listen({ port: 0 }, function () {
sget({
method: 'GET',
url: fastify.listeningOrigin + '/7'
}, (err, response, body) => {
t.error(err)
t.equal(response.statusCode, 200)
t.same(JSON.parse(body), { hello: 'world' })
})
})