Fastifyで内部APIと外部APIを実行する方法

Fastify.jsにおけるAPI連携の例を解説します。

概要

Fastify.jsは、Node.jsの軽量で高性能なWebアプリケーションフレームワークで、APIとの連携によく使用されます。APIとの連携を実現するためには、リクエストの送信やレスポンスの処理が必要となります。

ここでは、以下バージョンを使用した、Fastify.jsでAPIとの連携を行う方法を説明します。

Fastify.js v4.0.0
nodejs v19.7.0

また、今回作成するコードは全て、GitHubに掲載しています。

もちろんです。フロントエンドからAPIを実行する例として、JavaScriptを使用してFetch APIを使う方法について追記します。

フロントエンドからAPIを実行する方法

フロントエンドでAPIを使用することは一般的なシナリオで、JavaScriptのFetch APIを使うと簡単に実装できます。Fetch APIはブラウザがネイティブで提供するAPIで、非同期HTTP(Ajax)リクエストを行うことができます。

サーバー側の実装する前に、@fastify/staticプラグインを使用するため、以下コマンドを実行してインストールします。

npm install @fastify/static@latest

以下の例では、Fastify.jsで作成した/usersエンドポイントにPOSTリクエストを送信し、新しいユーザーを作成します。

server.js

// モジュールをインポートします
const fastify = require("fastify")({ logger: true });
const path = require("path");
const fs = require("fs");

// ユーザーを保存するための仮のデータストア
let users = [];

fastify.register(require("@fastify/static"), {
  root: path.join(__dirname, "views"),
  prefix: "/", // optional: default '/'
});
fastify.get("/users", (req, reply) => {
  // ユーザーデータをレスポンスとして返す
  reply.send(users);
});

fastify.post("/users", (req, reply) => {
  // リクエストボディからユーザーデータを取得
  const user = req.body;
  // ユーザーをデータストアに追加
  users.push(user);
  // 新しく作成されたユーザーをレスポンスとして返す
  reply.send(user);
});

fastify.listen({ port: 3000 }, (err) => {
  if (err) {
    console.error("サーバーの起動中にエラーが発生しました:", err);
    process.exit(1);
  }
  console.log("サーバーがポート3000で起動しました");
});

解説

このコードは、ユーザーの一覧と作成をサポートする基本的なFastifyサーバーを構築します。 以下に、それぞれの部分の詳細な説明を示します。

  • モジュールをインポート
const fastify = require("fastify")({ logger: true });
const path = require("path");

この部分では、fastifypathという2つのモジュールをインポートします。

  • HTMLファイルをホストするディレクトリを指定
fastify.register(require('@fastify/static'), {
  root: path.join(__dirname, 'views'),
  prefix: '/', // optional: default '/'
})

ここでは、@fastify/staticプラグインを使って、“views"というディレクトリの静的ファイルをホストします。

  • ユーザーデータを保存するための仮データストア
let users = [];

この部分では、作成されたユーザーを保存するための配列を定義します。

  • ルーティング
fastify.get("/", (req, reply) => {
  reply.sendFile('index.html') // serving path.join(__dirname, 'views', 'index.html') directly
});

fastify.get()メソッドを使って、ルートURL(”/")へのGETリクエストをハンドリングします。リクエストが来ると、“index.html"ファイルをレスポンスとして返します。

  • ユーザーデータの取得
fastify.get("/users", (req, reply) => {
  reply.send(users);
});

/usersへのGETリクエストが来たときに、保存されている全ユーザーの一覧をJSON形式でレスポンスとして返します。

  • ユーザーの作成
fastify.post("/users", (req, reply) => {
  const user = req.body;
  users.push(user);
  reply.send(user);
});

/usersへのPOSTリクエストが来たときに、リクエストボディからユーザーデータを取得し、それをデータストアに追加します。新しく作成されたユーザーをJSON形式でレスポンスとして返します。

  • サーバーの起動
fastify.listen(3000, (err, address) => {
  if (err) throw err
  fastify.log.info(`server listening on ${address}`)
})

最後に、サーバーを起動し、ポート3000でリッスンします。サーバーが起動すると、“server listening on {address}“というメッセージがコンソールに表示されます。

index.html

<!DOCTYPE html>
<html>
<body>
  <!-- ボタンを追加 -->
  <button onclick="createUser()">Create User</button>

  <script>
    async function createUser() {
      const response = await fetch('http://localhost:3000/users', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({ name: 'John', age: 25 })
      });

      if (!response.ok) {
        const message = await response.text();
        throw new Error(`An error has occurred: ${message}`);
      }

      const user = await response.json();

      console.log(user);
    }
  </script>
</body>
</html>

解説

このソースコードは、ユーザーを作成するためのHTMLページを生成します。

  • HTMLドキュメントの定義とボタンの追加:
<!DOCTYPE html>
<html>
<body>
    <!-- ボタンを追加 -->
    <button onclick="createUser()">Create User</button>

この部分では、HTML文書の基本的な構造を定義し、ユーザーを作成するためのボタンを追加しています。ボタンがクリックされるとcreateUser関数が実行されます。

  • createUser関数の定義:
<script>
async function createUser() {
    const response = await fetch('http://localhost:3000/users', {
        method: 'POST',
        headers: {
        'Content-Type': 'application/json'
        },
        body: JSON.stringify({ name: 'John', age: 25 })
    });

この部分で非同期関数createUserを定義しています。この関数は、fetchAPIを使用して、指定したURL(この場合はhttp://localhost:3000/users)に対してPOSTリクエストを送信します。リクエストボディには、作成するユーザーの情報をJSON形式で指定します。

  • エラーハンドリング:
    if (!response.ok) {
        const message = await response.text();
        throw new Error(`An error has occurred: ${message}`);
    }

response.okプロパティは、レスポンスが成功したかどうか(HTTPステータスコードが200~299の範囲かどうか)を判断します。成功していない場合、エラーメッセージを生成してエラーをスローします。

  • レスポンスの処理とログ出力:
const user = await response.json();

response.json()メソッドを使用して、レスポンスボディをJSONとして解析します。

最終的に以下のようなディレクトリ構成になります。

integration
├── node_modules
│   └── (依存関係のパッケージ)
├── views
│   └── index.html
├── server.js
├── package.json
└── package-lock.json

外部APIへのリクエストを送信する

外部APIへのリクエストを送信するためには、通常、HTTPクライアントライブラリが使用されます。ここでは、その一つであるaxiosを使用します。まず、npmを使ってaxiosをインストールします。

npm install axios
const fastify = require("fastify")({ logger: true });
const axios = require("axios");

fastify.get("/data", async (request, reply) => {
  try {
    const response = await axios.get(
      "https://jsonplaceholder.typicode.com/posts"
    );
    reply.send(response.data);
  } catch (error) {
    reply.status(500).send({ message: "Error occurred" });
  }
});

fastify.listen({ port: 3000 }, (err, address) => {
  if (err) throw err;
  fastify.log.info(`server listening on ${address}`);
});

解説

このコードは、JSONプレースホルダーAPIからデータを取得し、そのデータをレスポンスとして送信するFastifyサーバーを作成します。

  • モジュールのインポート:
const fastify = require('fastify')({ logger: true });
const axios = require('axios');

この部分で、fastifyaxiosという2つのモジュールをインポートします。fastifyはWebサーバーフレームワーク、axiosはHTTPクライアントライブラリです。

  • ルートの定義:
fastify.get('/data', async (request, reply) => {
  try {
    const response = await axios.get('https://jsonplaceholder.typicode.com/posts');
    reply.send(response.data);
  } catch (error) {
    reply.status(500).send({ message: 'Error occurred' });
  }
});

/dataエンドポイントにGETリクエストが来たときのハンドラーを定義します。非同期関数内でaxios.getを使って外部APIからデータを取得し、そのデータをレスポンスとして送信します。エラーが発生した場合は、ステータスコード500とエラーメッセージを含むレスポンスを送信します。

  • サーバーの起動:
fastify.listen({ port: 3000 }, (err, address) => {
  if (err) throw err;
  fastify.log.info(`server listening on ${address}`);
});

最後に、サーバーを起動し、ポート3000でリッスンします。サーバーが起動すると、“server listening on {address}“というメッセージがコンソールに表示されます。

テスト

curl http://localhost:3000/data

CURLコマンドを使用して、各エンドポイントの動作をテストすることができます。ただし、アプリケーションがポート3000で実行されていることを確認してください。また、必要に応じてホスト名やポート番号を変更してください。

まとめ

この記事では、Fastifyを使用してAPIを実行する方法を学びました。Fastifyは、Node.jsでAPIを構築するための高速で効率的なフレームワークです。Fastifyは、ExpressやKoaなどの他のフレームワークと比較しても、高速であることが知られています。Fastifyは、Node.jsのAPI開発において、高速で効率的なフレームワークとして人気を博しています。