fastify+TypeScriptの開発環境を作成してみた

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を使った開発が続きそうです。(笑)

コメント

PAGE TOP
タイトルとURLをコピーしました