Node.js で Undici を使用した Fetch API の利用

はじめに

Undici は Node.js の fetch API を支える HTTP クライアントライブラリです。これはゼロから書かれており、Node.js の組み込み HTTP クライアントに依存していません。高性能なアプリケーションに適した多くの機能が含まれています。

Undici の仕様準拠に関する情報については、Undici のドキュメントを参照してください。

基本的な GET の使用法

async function () {
  // Like the browser fetch API, the default method is GET
  const  = await ('https://jsonplaceholder.typicode.com/posts');
  const  = await .();
  .();
  // returns something like:
  //   {
  //   userId: 1,
  //   id: 1,
  //   title: 'sunt aut facere repellat provident occaecati excepturi optio reprehenderit',
  //   body: 'quia et suscipit\n' +
  //     'suscipit recusandae consequuntur expedita et cum\n' +
  //     'reprehenderit molestiae ut ut quas totam\n' +
  //     'nostrum rerum est autem sunt rem eveniet architecto'
  // }
}

().(.);

基本的な POST の使用法

// Data sent from the client to the server
const  = {
  : 'foo',
  : 'bar',
  : 1,
};

async function () {
  const  = await ('https://jsonplaceholder.typicode.com/posts', {
    : 'POST',
    : {
      'User-Agent': 'undici-stream-example',
      'Content-Type': 'application/json',
    },
    : .(),
  });
  const  = await .();
  .();
  // returns something like:
  // { title: 'foo', body: 'bar', userId: 1, id: 101 }
}

().(.);

Undici を使用した Fetch API のカスタマイズ

Undici を使用すると、fetch 関数にオプションを提供することで Fetch API をカスタマイズできます。例えば、カスタムヘッダーの設定、リクエストメソッドの設定、リクエストボディの設定が可能です。以下は、Undici を使用して Fetch API をカスタマイズする方法の例です。

fetch 関数は、取得する URL とオプションオブジェクトの2つの引数を取ります。オプションオブジェクトは、リクエストをカスタマイズするために使用できる Request オブジェクトです。この関数は、Response オブジェクトに解決される Promise を返します。

次の例では、JSON ペイロードを使用して Ollama API に POST リクエストを送信しています。Ollama は、ローカルマシンで LLM (大規模言語モデル) を実行できる CLI ツールです。こちらからダウンロードできます。

ollama run mistral

これにより、mistral モデルがダウンロードされ、ローカルマシンで実行されます。

プールを使用すると、同じサーバーへの接続を再利用できるため、パフォーマンスが向上します。以下は、Undici でプールを使用する方法の例です。

import {  } from 'undici';

const  = new ('https://:11434', {
  : 10,
});

/**
 * Stream the completion of a prompt using the Ollama API.
 * @param {string} prompt - The prompt to complete.
 * @link https://github.com/ollama/ollama/blob/main/docs/api.md
 **/
async function () {
  const { ,  } = await .request({
    : '/api/generate',
    : 'POST',
    : {
      'Content-Type': 'application/json',
    },
    : .({ , : 'mistral' }),
  });

  // You can read about HTTP status codes here: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
  // 200 means the request was successful.
  if ( !== 200) {
    throw new (`Ollama request failed with status ${}`);
  }

  let  = '';

  const  = new ();
  for await (const  of ) {
     += .(, { : true });
    .();
  }

  .('Streaming complete.');
}

try {
  await ('What is recursion?');
} catch () {
  .('Error calling Ollama:', );
} finally {
  .('Closing Ollama pool.');
  .close();
}

Undici でのストリーミング応答

ストリームは、データのチャンクを読み書きできる Node.js の機能です。

import {  } from 'stream';

import {  } from 'undici';

async function () {
  const  = 'https://api.github.com/users/nodejs/repos';

  const {  } = await (
    ,
    {
      : 'GET',
      : {
        'User-Agent': 'undici-stream-example',
        : 'application/json',
      },
    },
    () => {
      let  = '';

      return new ({
        (, , ) {
           += .toString();

          try {
            const  = .();
            .(
              'Repository Names:',
              .map( => .name)
            );
             = '';
          } catch () {
            .('Error parsing JSON:', );
          }

          ();
        },
        () {
          .('Stream processing completed.');
          ();
        },
      });
    }
  );

  .(`Response status: ${}`);
}

().(.);