APIをたたいてみる②NodeJSサーバーからリクエストを投げる

# 概要

https://qiita.com/flyaway2525/items/e262fa3e51c31daa2110

こちらの続きになります.  

APIを直に叩いて使う人はエンジニアだけです.
基本的には,ユーザーが保有するクライアントアプリケーションや,Webサーバーが外部連携(連携??)という形でたたきに行きます.

今回はNodeJSのサーバーからChatGPTのAPIにリクエストを投げます.
使用するのは以下で立てるReactのWebサーバーになります.

https://qiita.com/flyaway2525/private/650974931996f7b57aa2

## 接続に必要な情報
APIを叩くには以下の3つが必要なことがあります.  
 - エンドポイント
     - URLです,アクセスする先を指定します.
 - APIキー
     - 叩いていい権限があるかチェックするために用いります.
 - リクエスト文
     - 何をしたいか記述します.
     - 内容はAPIサーバーの中身に依存します.

## ソースコード
色々な事情で不要な部分もありますが,APIを叩く部分についてちゃんと解説します.
<details><summary>今回使用しているソースコードをそのまま記載します.</summary>

```tsx
// server/pages/azure_ai_connection_test.tsx

import { customLog } from "@/utils/customLog";

const API_KEY: string = process.env.AZURE_AI_API_KEY_CHATGPT35!;
const AZURE_AI_SERVER_URL: string = process.env.AZURE_AI_SERVER_URL!;

async function fetchData() {
  const headers = new Headers();
  headers.append("api-key", API_KEY);
  headers.append("Content-Type", "application/json");

  const body = JSON.stringify({
      "messages": [
        {
          "role": "system",
          "content": "You are an AI assistant that helps people find information."
        }
      ],
      "temperature": 0.7,
      "top_p": 0.95,
      "frequency_penalty": 0,
      "presence_penalty": 0,
      "max_tokens": 800,
      "stop": null
    }
  );

  const requestOptions = {
    method: "POST",
    headers: headers,
    body: body
  };

  // ビルドするたびにAPIが走るので,回避中
  customLog("実行にはソースの修正が必要です.","DEBUG");
  //return {context: "実行にはソースの修正が必要です."};
  const response = await fetch(AZURE_AI_SERVER_URL, requestOptions);
  let data = undefined;
  if (response.ok) {
    data = await response.json();
    customLog(data, "DEBUG");
  } else {
    console.log('Network response was not ok');
  }
  return { context: data };
}

// ページコンポーネント
function HelloAzureAI({ context }: any) {
  return (
    <div>
      <h1>TestJson!!</h1>
      <pre>{JSON.stringify(context, null, 2)}</pre>
    </div>
  );
}

// サーバーサイドでデータを取得する関数
export async function getServerSideProps() {
  const data = await fetchData();
  return { props: { ...data } };
}

export default HelloAzureAI;

```

</details>

## ソース解説

### リクエスト実行部分
APIを叩くときの根幹部分はこちらになります.

```tsx
const response = await fetch(AZURE_AI_SERVER_URL, requestOptions);
  let data = undefined;
  if (response.ok) {
    data = await response.json();
    console.log('データ取得できました.');
  } else {
    console.log('レスポンスがありません.');
  }
```

 - `AZURE_AI_SERVER_URL` : エンドポイントが入ります.(string形式)
 - `requestOptions` : リクエストに必要な情報が入ります.
 - `data` : 取得したデータを入れます.

---

### requestOptions
では,`requestOptions`の中身を解説します.
また,下記のものが格納されていればいいので,`requestOptions`という名前でなくてもいいです.  

```tsx
  const requestOptions = {
    method: "POST",
    headers: headers,
    body: body
  };
```
 - `method` : HTTPリクエストのタイプを指定します.
     - [なぜPOSTを使用するかわからなければ各自調べる.](https://developer.mozilla.org/ja/docs/Web/HTTP/Methods)
 - `headers` : リクエストのメタデータを入れます.今回だと`API-KEY`情報など
 - `body` : リクエストのデータを入れます.今回だとAIへの質問文など

---

### headers
ヘッダー情報にはAPI_KEYの情報と,「リクエストをJson形式で送る」というメタ情報を送る.  
```tsx
  const API_KEY: string = "abcd123abcd123abcd123abcd123";

  
  const headers = new Headers();
  headers.append("api-key", API_KEY);
  headers.append("Content-Type", "application/json");
```

### body
ボディーには今回使用するChatGPTの公式リファレンスにのっとって必須の項目や,オプションで設定できる項目を記述する.  
詳細は下記参照

https://qiita.com/flyaway2525/items/4549a8c9931854db5eb0

https://platform.openai.com/docs/api-reference

```tsx
  const body = JSON.stringify({
      "messages": [
        {
          "role": "system",
          "content": "You are an AI assistant that helps people find information."
        }
      ],
      "temperature": 0.7,
      "top_p": 0.95,
      "frequency_penalty": 0,
      "presence_penalty": 0,
      "max_tokens": 800,
      "stop": null
    }
  );
```

本来本家ChatGPTのAPIであれば,AIのmodel名の指定が必須条件になっているが,AzureOpenAIを指定しており,エンドポイントに対してモデルが決まっているため不要.
他条件については妥当なもの,標準設定を行っている.

### 出力結果
今回のソースでは,返ってきたレスポンスデータをすべてそのまま画面に出している.
これらの情報の内,使用したいものを厳選して使用する.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1505183/758215c4-e6cd-010a-3ad0-df775dbc09bc.png)

例えば,
`data.choices[0].message.content`を指定すれば
`Hello, I am an AI assistant designed to help you find information. How may I assist you today?`というAIの返答のみを取得できます.

# 終わりに
今回はAPIを叩いてみた.
また,APIの枠組みを簡単に説明した.
何かわからないこと等あれば質問いただけると幸いです！