node.jsでWebアプリ開発と言えば、Expressが有名だけど、最近他にもWebサーバのミドルウェアがあることを知りました。
中でも、最速のWebサーバとして、fastifyというミドルウェアが最近注目を浴びているようです。
というわけで、今回はfastifyを使ったWebサーバアプリプロジェクトを作成してみることにします。
目次
開発環境
個人的にTypeScriptが好きなため、今回はTypeScriptを使った開発環境を作成します。
今回は以下のミドルウェアを使用します。
・TypeScript
・fastify
・fastify-decorators
fastify-decoratorsは、fastifyでDI開発を行うためのデコレータライブラリです。
統合開発環境は、VisualStudio Code(VSCode)を使用します。
また、パッケージ管理はnpmを使用します。
プロジェクトの作成
ディレクトリ構成の作成
今回のプロジェクトのディレクトリ構成を以下に示します。
fastifybase dist src controller
一般なTypeScriptのプロジェクト構成は、srcディレクトリにTypeScriptコードを書いて、トランスパイルしたスクリプトをdistディレクトリに出力する構成が多い。
今回作成するプロジェクトも、その構成に従うこととします。
今回作成するプロジェクト名は、fastifybaseとしています。
プロジェクトの作成
まずは、エクスプローラで、上記に記載したディレクトリ構成を作成します。
その後、VSCodeを起動して、作成したfastifybaseディレクトリを開きます。
PowerShellコンソールで、以下のコマンドを入力して、プロジェクトの初期化を行います。
npm init -y git init
npmだけでなく、gitの初期化も行っていますが、これはgitでソース管理をすることを想定したものです。
その後、プロジェクト直下のディレクトリに、手動で.gitignoreファイルを作成します。
エディタで開いて、以下の一文を書いて保存します。
/node_modules/
これにより、node_modulesディレクトリのファイルはgitの管理外になります。
必要なライブラリのインストール
次に、今回使用するパッケージのインストールを行います。
PowerShellコンソールで、以下のコマンドを入力します。
① TypeScriptのインストール
npm install typescript ts-node @types/node --save-dev
② fastifyおよびfastify-decoratorsのインストール
npm install fastify fastify-decorators path --save
pathはプログラムで使用するので、ついでにインストールしておきます。
tsconfig.jsonの設定
次にTypeScriptの設定を行ないます。
まず、以下のコマンドを実行して、tsconfig.jsonを作成します。
tsc --init
エディタでtsconfig.jsonを開いて、以下の設定を行ないます。
{ "compilerOptions": { "outDir": "./dist/", "module": "commonjs", "target": "es6", "experimentalDecorators": true }, "include": [ "./src/**/*" ] }
TypeScriptのソースはsrc下に書いて、トランスパイルしたソースをdistに出力するので、includeとoutDirの設定を行ないます。
また、今回はfastify-decoratorsでデコレータを使用するため、experimentalDecoratorsにtrueを設定する必要があります。
以上で、プロジェクトの準備は完了です。
実装の作成
それでは、処理の作成を行っていきます。
今回は、ブラウザでhttp://localhost:3000/hello/にアクセスしたら、画面に「Hello World」と表示されるだけの、至って簡単な処理を作成します。
index.ts
まず、index.tsでWebサーバを起動する処理を書きます。
ソースは、以下のようになっています。
import fastify from 'fastify'; import { bootstrap } from 'fastify-decorators'; import path from 'path'; // Require the framework and instantiate it const instance = fastify(); // Register handlers auto-bootstrap instance.register(bootstrap, { // Specify directory with our handler directory: path.resolve(__dirname, `controllers`), // Specify mask to match only our handler mask: /\.controller\./, }); // Run the server! instance.listen(3000);
instance.registerでは、fastify-decoratorsのcontrollerクラスの設定を行なっています。
directoryでは、controllerクラスを置くディレクトリの指定を、maskはcontrollerクラスファイルの名称の規則を定義します。
今回は、controllerクラスファイルは、必ず.controller.をつけるように設定します。
コントローラの作成
次に、controllerの実装を行ないます。
上記の設定に従い、今回はcontrollerディレクトリに、hello.controller.tsというファイル名のファイルを作成します。
ソースの内容を以下に記載します
import { FastifyRequest, FastifyReply } from 'fastify'; import { Controller, GET, ErrorHandler } from 'fastify-decorators'; class MyError extends Error {} @Controller({ route: '/' }) export default class HelloController { @GET({ url: '/hello' }) hello(request: FastifyRequest, reply: FastifyReply) { return 'Hello World!'; } @GET({ url: '/error' }) error(request: FastifyRequest, reply: FastifyReply) { throw new MyError('My Error') } @ErrorHandler(MyError) handleError(error: MyError, request: FastifyRequest, reply: FastifyReply) { reply.status(500).send({ message: 'Internal Server Error' }); } }
controllerクラスには、必ず@Controllerデコレータを設定します。
routeでこのcontrollerがどのパスを定義したものかを指定します。
今回は/なので、ルートパスを指定したことになります。
クラス下のメソッドには、HTTPメソッドに対応したデコレータを指定します。
今回はGETメソッドなので、@GETデコレータを指定し、パスに/helloを設定します。
これで、http://localhost:3000/hello/を実行したら、HelloControllerクラスのhelloメソッドが呼び出されるようになります。
なお、メソッドの引数は、Expressと同じように、HTTPリクエストに相当するFastifyRequestオブジェクトと、HTTPレスポンスに相当するFastifyReplyオブジェクトになります。
hello関数では、Hello World!という文字列を返してますが、fastifyの場合は、returnで返した値がそのままレスポンスになるようです
Expressの場合は、引数のHttpResponseオブジェクトのsendメソッド等でレスポンスを設定していたので、ここが少しExpressと異なる点になります。
もっとも、レスポンスヘッダーやCookieの設定したり、ファイルのダウンロード処理を行なったり、複雑なレスポンスを返す場合は、Expressと同じように、引数のFastifyReplyオブジェクトで処理を行う必要があるようです。
エラーハンドラの実装は、@ErrorHandlerで行います。
エラーハンドラでは、特定の例外クラスに対する関数を定義することができます。
上記の例では、MyErrorという例外がスローされた場合に、handleError関数が実行されます。
MyErrorエラーをスローするerror関数を定義しています。
ブラウザでhttp://localhost:3000/error/を実行したら、error関数が実行されて、その中でMyErrorエラーがスローされるので、handleError関数が実行されます。
ブラウザに、{ message: ‘Internal Server Error’ }と表示されると思います。
アプリの実行
作成したプログラムを実行するために、package.jsonおよびlaunch.jsonの設定を行ないます。
package.jsonスクリプトの作成
エディタでpackage.jsonを開いて、以下のスクリプトを追加します。
"scripts": { "build": "tsc", "start": "node dist/index.js", "debug": "ts-node src/index.ts" },
buildは、TypeScriptソースをトランスパイルするためのコマンドで、startはトランスパイルしたJavaScriptコードを実行するためのコマンドになります。
debugはTypeScriptのままデバッグを行うためのコマンドで、ts-nodeを使用します。
VSCodeからデバッグ
VSCodeでデバッグを行う場合は、launch.jsonにts-nodeを使ったデバッグ定義を追加する必要があります。
他のnode.jsと違って、少し独特の記載方法になります。
{ "type": "node", "request": "launch", "name": "プロジェクトのデバッグ", "args": ["${workspaceRoot}/src/app.ts"], "runtimeArgs": ["-r", "ts-node/register"], "cwd": "${workspaceRoot}", "protocol": "inspector", "internalConsoleOptions": "openOnSessionStart", "env": { "TS_NODE_IGNORE": "false" } }
これで、VSCode上でTypeScriptコードのデバッグが可能になります。
使ってみた感想
今回、初めてfastifyを使って処理を書いてみましたが、正直言ってこれだけのコードでは速さは実感できませんでした。
(まあ、hello Worldだけですし。)
本格的に処理を書いてみたら、処理速度の差が実感できるかもしれません。
あと、fastifyに関する情報は、今はまだかなり少ないです。
特に、fastify-decoratorsに関する情報は、公式サイト以外はほとんどありません。
なので、本格的な開発を行う場合は、色々苦労するかもしれません。
ただ、fastifyの注目度は高く、使用件数は急速に増加しているため、今後は開発情報が増えてくると思われます。
ちなみに、私はまだ当分Expressを使った開発が続きそうです。(笑)
コメント