Hapi(hapi.js)とは?Node.jsでの特徴・使い方・Express比較と導入ポイント【入門】

Hapi(ハピ)とは — 概要

Hapi(一般に hapi または hapi.js と呼ばれる)は、Node.js 上で動作するサーバーサイドのフレームワークです。直訳すると「構成志向(configuration-driven)」でプラグインベースの設計を特徴とし、API サーバーやマイクロサービス、社内サービスなど堅牢で保守性の高いサーバー実装を目的として設計されています。Hapi は設定(route 定義、バリデーション、認証、キャッシュ等)を明示的に記述することで、コードの可読性と一貫性を高めることを重視します。

簡単な歴史と背景

Hapi は Walmart Labs(当時)のエンジニア、Eran Hammer 氏らによって開発され、2011 年頃にオープンソース化されました。設計思想は、複雑な企業向けアプリケーションで要求される「プラグイン化」「明確なライフサイクル」「拡張性」「テストしやすさ」を満たすことにあります。コミュニティとプラグイン群を中心に発展し、テンプレートエンジン連携や静的ファイル配信、各種認証方式などのエコシステムが整っています。

Hapi の主要コンセプト

  • サーバーとルートの明示的な定義 — ルート(メソッド、パス、ハンドラ、設定)は宣言的に定義し、ミドルウェア的な暗黙の振る舞いを避けます。
  • プラグインベースの拡張 — 機能はプラグインとして分離・登録して使うことが推奨されます。プラグインは名前空間、依存関係、初期化ロジックを持てます。
  • リクエストライフサイクル — リクエストの入出力に対する一連のフック(拡張ポイント)があり、前処理・後処理やエラー処理を適切に差し込みやすい設計です。
  • 入力バリデーションの標準化 — 入力(クエリ、ボディ、ヘッダ、パス)に対するバリデーションをルート定義に組み込めます。一般的に Joi ライブラリが使われます。
  • 認証・認可の統合 — 認証ストラテジーをプラグインとして登録し、ルートごとに適用できます。
  • 明示的なエラーとレスポンス処理 — エラー処理やレスポンス加工もライフサイクルで明確に扱えます。

主要機能の詳細

以下は Hapi を使う上で頻繁に利用する主要機能と特徴です。

ルーティング

ルートは verbose かつ宣言的に定義します。HTTP メソッド、パス、ハンドラ、設定オブジェクト(バリデーションや認証など)を一箇所にまとめることで何を期待するルートなのかが明確になります。

バリデーション(Joi)

入力バリデーションは Joi(現在は Joi の公式サイトや GitHub:joi.dev を参照)と組み合わせて使うのが定番です。リクエストごとに schema を指定して、パース・検証・サニタイズを行えます。これによりハンドラ内の守りが薄くても安全な設計が可能になります。

プラグインとエコシステム

Hapi 本体は小さなコアを持ち、機能拡張はプラグインで行います。公式・コミュニティにより以下のようなプラグインが提供されています(例):

  • Inert:静的ファイル配信
  • Vision:テンプレートエンジン連携(ビュー)
  • Bell:OAuth / OAuth2 / SNS 認証(外部ログイン)用プラグイン
  • hapi-auth-jwt2 やその他の認証プラグイン:JWT や Cookie ベースの認証

キャッシュとセッション

内部にキャッシュ抽象化があり、メモリや外部キャッシュ(Redis など)を使いやすく統合できます。状態管理やセッションに対してもプラグインで柔軟に対応可能です。

テストとモジュール性

プラグイン単位で機能を分割しやすいため、ユニットテストや統合テストが書きやすいという利点があります。ライフサイクルフックを使ってテスト時のセットアップ・ティアダウンを行うことが一般的です。

簡単な使用例

以下は Hapi サーバーの簡単な例です(Node.js 環境想定)。このコードは WordPress の投稿に貼るためにそのまま表示できるよう pre/code で囲っています。

const Hapi = require('@hapi/hapi');
const Joi = require('joi');

(async () => {
  const server = Hapi.server({ port: 3000, host: 'localhost' });

  server.route({
    method: 'GET',
    path: '/',
    options: {
      validate: {
        query: Joi.object({
          name: Joi.string().min(1).max(100).optional()
        })
      }
    },
    handler: (request, h) => {
      const name = request.query.name || 'World';
      return { message: `Hello, ${name}!` };
    }
  });

  await server.start();
  console.log('Server running on %s', server.info.uri);
})();

Express と比較した際の特徴

  • 設計思想:Express はミニマルでミドルウェアチェーンにより処理を構成するのに対し、Hapi は宣言的・設定重視でプラグインを中心に設計される。
  • バリデーションと設定:Hapi はルートごとにバリデーションや認証を設定する仕組みが標準化されているため大規模アプリでの一貫性が出しやすい。
  • プラグインモデル:どちらも拡張可能だが、Hapi のプラグインは名前空間や依存記述などが組み込みで用意されており、大規模開発での管理がやりやすい。

いつ Hapi を選ぶべきか

次のようなケースで Hapi の採用は有力な選択肢になります。

  • 大規模な API サーバーや複数チームで開発するサービスで、一貫性ある設定・認証・バリデーションが求められる場合
  • プラグイン単位で機能を分割したい、または再利用可能な機能群を作りたい場合
  • 明確なライフサイクル制御や拡張ポイント(前処理・後処理)が重要な場合

一方で、小さく迅速にプロトタイプを作るだけなら Express や Fastify の方が導入コストは低いこともあります。

注意点と運用上のポイント

  • パッケージ名やエコシステムの変更に注意:Hapi 周りの関連パッケージ(Joi や公式プラグイン)は過去に名前空間やメンテナンス体制が変わってきた歴史があり、利用時は公式ドキュメントや npm の最新版を確認すること。
  • バージョン互換性:重大なメジャーアップデートで API が変わることがあるため、マイグレーションガイドを確認すること。
  • セキュリティ:入力検証や認証の設定をルート単位で確実に行う。デフォルト設定だけに頼らずプラグインとルールを適切に組み合わせる。

まとめ

Hapi は「設定とプラグイン」で拡張することを前提に設計された Node.js フレームワークであり、企業向けや大規模 API、セキュリティや整合性が重要なサービスに向いています。宣言的なルーティング、Joi を用いた強力なバリデーション、プラグインによる機能分離・再利用性などを通じて、保守性の高いコードベースを構築できる点が最大の強みです。選択にあたってはプロジェクト規模、チーム構成、既存のエコシステムとの相性を踏まえて検討してください。

参考文献