データベース
データベース
Fastifyのエコシステムは、さまざまなデータベースエンジンに接続するための多数のプラグインを提供しています。このガイドでは、Fastify組織内で管理されているFastifyプラグインがあるエンジンについて説明します。
選択したデータベースのプラグインが存在しない場合でも、Fastifyはデータベースに依存しないため、データベースを使用できます。このガイドにリストされているデータベースプラグインの例に従うことで、欠落しているデータベースエンジン用のプラグインを作成できます。
独自のFastifyプラグインを作成する場合は、プラグインガイドをご覧ください。
MySQL
npm i @fastify/mysql
を実行してプラグインをインストールします。
使用方法
const fastify = require('fastify')()
fastify.register(require('@fastify/mysql'), {
connectionString: 'mysql://root@localhost/mysql'
})
fastify.get('/user/:id', function(req, reply) {
fastify.mysql.query(
'SELECT id, username, hash, salt FROM users WHERE id=?', [req.params.id],
function onResult (err, result) {
reply.send(err || result)
}
)
})
fastify.listen({ port: 3000 }, err => {
if (err) throw err
console.log(`server listening on ${fastify.server.address().port}`)
})
Postgres
npm i pg @fastify/postgres
を実行してプラグインをインストールします。
例:
const fastify = require('fastify')()
fastify.register(require('@fastify/postgres'), {
connectionString: 'postgres://postgres@localhost/postgres'
})
fastify.get('/user/:id', function (req, reply) {
fastify.pg.query(
'SELECT id, username, hash, salt FROM users WHERE id=$1', [req.params.id],
function onResult (err, result) {
reply.send(err || result)
}
)
})
fastify.listen({ port: 3000 }, err => {
if (err) throw err
console.log(`server listening on ${fastify.server.address().port}`)
})
Redis
npm i @fastify/redis
を実行してプラグインをインストールします
使用方法
'use strict'
const fastify = require('fastify')()
fastify.register(require('@fastify/redis'), { host: '127.0.0.1' })
// or
fastify.register(require('@fastify/redis'), { url: 'redis://127.0.0.1', /* other redis options */ })
fastify.get('/foo', function (req, reply) {
const { redis } = fastify
redis.get(req.query.key, (err, val) => {
reply.send(err || val)
})
})
fastify.post('/foo', function (req, reply) {
const { redis } = fastify
redis.set(req.body.key, req.body.value, (err) => {
reply.send(err || { status: 'ok' })
})
})
fastify.listen({ port: 3000 }, err => {
if (err) throw err
console.log(`server listening on ${fastify.server.address().port}`)
})
デフォルトでは、@fastify/redis
はFastifyサーバーがシャットダウンしてもクライアント接続を閉じません。この動作を有効にするには、次のようにクライアントを登録します
fastify.register(require('@fastify/redis'), {
client: redis,
closeClient: true
})
Mongo
npm i @fastify/mongodb
を実行してプラグインをインストールします
使用方法
const fastify = require('fastify')()
fastify.register(require('@fastify/mongodb'), {
// force to close the mongodb connection when app stopped
// the default value is false
forceClose: true,
url: 'mongodb://mongo/mydb'
})
fastify.get('/user/:id', async function (req, reply) {
// Or this.mongo.client.db('mydb').collection('users')
const users = this.mongo.db.collection('users')
// if the id is an ObjectId format, you need to create a new ObjectId
const id = this.mongo.ObjectId(req.params.id)
try {
const user = await users.findOne({ id })
return user
} catch (err) {
return err
}
})
fastify.listen({ port: 3000 }, err => {
if (err) throw err
})
LevelDB
npm i @fastify/leveldb
を実行してプラグインをインストールします
使用方法
const fastify = require('fastify')()
fastify.register(
require('@fastify/leveldb'),
{ name: 'db' }
)
fastify.get('/foo', async function (req, reply) {
const val = await this.level.db.get(req.query.key)
return val
})
fastify.post('/foo', async function (req, reply) {
await this.level.db.put(req.body.key, req.body.value)
return { status: 'ok' }
})
fastify.listen({ port: 3000 }, err => {
if (err) throw err
console.log(`server listening on ${fastify.server.address().port}`)
})
データベースライブラリのプラグインの作成
データベースライブラリ(例:Knex、Prisma、またはTypeORM)用のプラグインも作成できます。この例では、Knexを使用します。
'use strict'
const fp = require('fastify-plugin')
const knex = require('knex')
function knexPlugin(fastify, options, done) {
if(!fastify.knex) {
const knex = knex(options)
fastify.decorate('knex', knex)
fastify.addHook('onClose', (fastify, done) => {
if (fastify.knex === knex) {
fastify.knex.destroy(done)
}
})
}
done()
}
export default fp(knexPlugin, { name: 'fastify-knex-example' })
データベースエンジンのプラグインの作成
この例では、基本的なFastify MySQLプラグインをゼロから作成します(これは簡略化された例です。本番環境では公式プラグインを使用してください)。
const fp = require('fastify-plugin')
const mysql = require('mysql2/promise')
function fastifyMysql(fastify, options, done) {
const connection = mysql.createConnection(options)
if (!fastify.mysql) {
fastify.decorate('mysql', connection)
}
fastify.addHook('onClose', (fastify, done) => connection.end().then(done).catch(done))
done()
}
export default fp(fastifyMysql, { name: 'fastify-mysql-example' })
マイグレーション
データベーススキーマのマイグレーションは、データベース管理と開発に不可欠な部分です。マイグレーションは、データベースのスキーマを変更し、データ損失を防ぐための、再現可能でテスト可能な方法を提供します。
ガイドの冒頭で述べたように、Fastifyはデータベースに依存せず、任意のNode.jsデータベースマイグレーションツールを使用できます。ここでは、Postgres、MySQL、SQL Server、およびSQLiteをサポートするPostgratorを使用する例を示します。MongoDBのマイグレーションについては、migrate-mongoを確認してください。
Postgrator
Postgratorは、SQLスクリプトのディレクトリを使用してデータベーススキーマを変更するNode.js SQLマイグレーションツールです。マイグレーションフォルダー内の各ファイルは、[バージョン].[アクション].[オプションの説明].sql
というパターンに従う必要があります。
バージョン:は、インクリメントされる数値である必要があります(例:001
またはタイムスタンプ)。
アクション:は、do
またはundo
である必要があります。do
はバージョンを実装し、undo
は元に戻します。他のマイグレーションツールでのup
およびdown
のように考えてください。
オプションの説明は、どの変更をマイグレーションが行うかを説明します。オプションですが、すべてのマイグレーションで使用する必要があります。これにより、誰もがマイグレーションでどの変更が行われたかを簡単に知ることができます。
この例では、users
テーブルを作成する単一のマイグレーションがあり、Postgrator
を使用してマイグレーションを実行します。
npm i pg postgrator
を実行して、例に必要な依存関係をインストールします。
// 001.do.create-users-table.sql
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY NOT NULL,
created_at DATE NOT NULL DEFAULT CURRENT_DATE,
firstName TEXT NOT NULL,
lastName TEXT NOT NULL
);
const pg = require('pg')
const Postgrator = require('postgrator')
const path = require('node:path')
async function migrate() {
const client = new pg.Client({
host: 'localhost',
port: 5432,
database: 'example',
user: 'example',
password: 'example',
});
try {
await client.connect();
const postgrator = new Postgrator({
migrationPattern: path.join(__dirname, '/migrations/*'),
driver: 'pg',
database: 'example',
schemaTable: 'migrations',
currentSchema: 'public', // Postgres and MS SQL Server only
execQuery: (query) => client.query(query),
});
const result = await postgrator.migrate()
if (result.length === 0) {
console.log(
'No migrations run for schema "public". Already at the latest one.'
)
}
console.log('Migration done.')
process.exitCode = 0
} catch(err) {
console.error(err)
process.exitCode = 1
}
await client.end()
}
migrate()