🦄

Elysia.jsを始める【Life Cycle】

2024/09/16に公開

※ この記事は、https://elysiajs.com/essential/life-cycle.html を日本語に翻訳しながら要点をまとめたものになるので、詳細は公式を確認してください。

Elysia.jsでのライフサイクル図

Events

Elysiaでのライフサイクルの大まかな概要は以下となる。

イベント名 内容
Request 新しいイベントを受信した時に通知される。この際、オーバーヘッドを減らすために最小限のコンテキストのみが提供される。
Parse リクエストのあったbodyを解析し、Context.bodyへ内容を追加する。
Transform バリデーション前に既存のコンテキストをバリデーションに適合させるために修正したり、あたらしいコンテキストを追加する。
Validation 受信したリクエストのバリデーション
Before Handle ルートハンドラー処理(Handle)に入る前に、カスタムバリデーションを行うことができる。
Handle(ルートハンドラー) 各ルートの処理
After Handle 返却値をレスポンスにマッピングする。カスタムヘッダーを追加したり、値を新しいレスポンスに変換することなどができる。
Error throwされたエラーをキャッチする。カスタムエラーレスポンスを処理したり、エラーレスポンスをキャッチすることなどができる。
After Response クライアントにレスポンスが送信された後に実行される。

Hook

Elysiaで、ライフサイクルイベント中に利用できるhookは、大まかに2種類。

  • Local Hook
  • Interceptor Hook

の2種類ある。

Local Hook

特定のルートに対してのみ実行されるフック。
ルートハンドラー内で、インラインで設定ができる。

Local Hook(ローカルフック)の例

import { Elysia } from 'elysia'
import { isHtml } from '@elysiajs/html';

const app = new Elysia()
  .get('/mikochi', () => '<h1>NyaHello World !!</h1>', {
    afterHandle({ response, set }) {
      if (isHtml(response)) {
        set.headers['content-type'] = 'text/html; charset=utf8'
      }
    }
  })
  .get('/subaru', () => '<h1>Ajimaru! Ajimaru!</h1>')
  .listen(3000)

上記を実行して、ブラウザで確認すると(ブラウザのNetworkタブで確認できる)、

path content-type
/mikochi text/html; charset=utf8
/subaru text/plain;charset=utf-8

となる。

/mikochiのブラウザでの確認画像

/subaruのブラウザでの確認画像

ちなみに...

上記の表と画像を見てもらうとわかるがset.headersの設定値は、設定した通りに反映される模様。
/mikochiのルートパスで、text/html;charset=utf8の間に半角スペースを入れて確認したところ、半角スペースはそのままになっていた。
また、charsetの値もutf8を代入した場合、ブラウザ側ではutf-8と修正されずにutf8として認識されていた。

Interceptor Hook

Interceptor Hookとして記述した後のルートハンドラーすべてに、記述したHookを適用する。

import { Elysia } from 'elysia'
import { isHtml } from '@elysiajs/html';

const app = new Elysia()
  .get('/mikochi', () => '<h1>NyaHello World !!</h1>')
  .onAfterHandle(({ response, set }) => {
    if (isHtml(response)) {
      set.headers['content-type'] = 'text/html; charset=utf-8'
    }
  })
  .get('/subaru', () => '<h1>Ajimaru! Ajimaru!</h1>')
  .get('/fubuki', () => '<h1>Hi! Friends!!</h1>')
  .listen(3000)

上記の場合、onAfterHandle()の記述より下のルートハンドラーにHook内の処理である、set.handlerが適用される。
そのため、/mikochiのみheadersのcontent-typeに'text/html; charset=utf-8'が登録されない。

path content-type
/mikochi text/plain;charset=utf-8
/subaru text/html;charset=utf-8
/fubuki text/html;charset=utf-8

/mikochiのブラウザでの確認画像

/subaruのブラウザでの確認画像

/fubukiのブラウザでの確認画像

コードの順番

Elysiaのイベントのライフサイクルは、キューとして管理・登録される。
そのため、キューへ登録した順にFIFO(先入先出し)でコードが実行される。

import { Elysia } from 'elysia'

const app = new Elysia()
  .onBeforeHandle(() => {
    console.log('mikochi')
  })
  .onAfterHandle(() => {
    console.log('subaru')
  })
  .get('/fubuki', () => '<h1>Hi! Friends!!</h1>', {
    beforeHandle() {
      console.log('shirakami')
    }
  })
  .listen(3000)

上記例だと、

  1. onBeforeHandle()を実行 → 出力:mikochi
  2. get()内の、beforeHandle()を実行 → 出力:shirakami
  3. onAfterHandle()を実行 → 出力: subaru

という順番になる。

Discussion