非同期関数でAPIを触ってみる

# 初めに

Next.jsの案件でSSGでデータを取得する実装をした際に、非同期処理について理解が浅かったので　APIからデータを取得して表示するプロセスにおいて、今回はSSG（Static Site Generation）の説明は割愛し、<font color="red">**非同期関数**</font>に焦点を当てて振り返りたいと思います。

大まかに以下3つの流れに沿って、書いていきます。

・APIエンドポイントの準備
・データ取得のフェッチ処理
・データの表示

## 非同期関数とは

以下、ChatGPTに聞いてみました。

> APIからデータを取得するような時間がかかる操作を非同期的に処理するための関数です。非同期関数は主に```async``` と ```await```キーワードを使用して記述され、これによりJavaScriptの実行を停止することなく、バックグラウンドでデータのロードやその他のタスクを完了させることができます。

# ディレクトリの構造について

![my-image-name.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3536873/6de86721-6547-2682-2890-17cb47e62445.png)


# APIエンドポイントの準備

## APIエンドポイントとは

APIエンドポイントとは、<font color="red">**APIが提供する特定のURLであり、クライアントがリクエストを送り、APIの仕様に基づいたデータを返す役割**</font>をします。

以下の手順に従って、APIエンドポイントを作成していきます。

・APIルートファイルの作成
・API応答用の初期データ設定
・応答遅延とデータの返却

## APIルートファイルの作成

ファイルの位置については、```pages/``` ディレクトリ内に新しいファイルを作成します。ファイル名やディレクトリ構造がそのままURLのパスになります。例えば、```pages/api/todos/index.ts``` は ```http://localhost:3000/api/todos``` に対応します。

### コード全体
```typescript
import { NextApiRequest, NextApiResponse } from "next";

type Todo = {
  title: string;
}

const todos: Todo[] = [
  { title: "読書" },
  { title: "プログラミング" },
  { title: "散歩" },
];

export default async (req: NextApiRequest, res: NextApiResponse) => {
  await new Promise((resolve) => setTimeout(resolve, 4000));

  res.status(200).json(todos);
};
```

## API応答用の初期データ設定

```type``` を使用してTodo型を定義しています。これは、```title``` という名前の文字列型のプロパティを持つオブジェクトの型です。この```title```プロパティは、各TODOアイテムのタイトルを表しています。```type```はTypeScriptでカスタムのデータ型を作成するための構文です。

```typescript
type Todo = {
  title: string;
}
```

```todos``` 配列は、Todo型のオブジェクトを要素として含んでおり、事前に定義されたTODOリストを表しています。この配列には「読書」、「プログラミング」、「散歩」というタイトルを持つ3つのタスクが含まれています。

```typescript
const todos: Todo[] = [
  { title: "読書" },
  { title: "プログラミング" },
  { title: "散歩" },
];
```

## 応答遅延とデータの返却

```await new Promise((resolve) => setTimeout(resolve, 4000));``` この行は、APIの応答を意図的に4秒遅延させています。

```res.status(200).json(todos);``` この行は、HTTPステータスコード200（成功）とともに、todosという名前のデータ配列をJSON形式でクライアントに返しています。これにより、APIを呼び出したクライアントは正常にデータを受け取ることができます。

```typescript
export default async (req: NextApiRequest, res: NextApiResponse) => {
  await new Promise((resolve) => setTimeout(resolve, 4000));

  res.status(200).json(todos);
};
```

# データ取得のフェッチ処理

上記で作成したAPIを、取得してから表示するまでのファイルを作成します。ファイルの位置については、```app/todos/``` ディレクトリ配下に ```page.tsx``` ファイルを置きます。

### コード全体

```typescript
import Link from "next/link";

type Todo = {
  title: string;
};

async function getData() {
  const res = await fetch("http://localhost:3000/api/todos");
  return res.json();
}

export default async function Page() {

  const todos: Todo[] = await getData();

  return (
    <>
      <h1>Todos</h1>
      {todos.map((todo) => (
        <div key={todo.title}>{todo.title}</div>
      ))}
      <Link href="/">Home</Link>
    </>
  );
}

```

```getData``` は非同期関数で、```fetch``` を使用して指定されたURL（```http://localhost:3000/api/todos```）からデータを取得します。fetch関数はAPIからのレスポンスを取得し、そのレスポンスをJSON形式で解析します。この関数は解析されたデータを返します。

```typescript
async function getData() {
  const res = await fetch("http://localhost:3000/api/todos");
  return res.json();
}
```

# データの表示

getData関数を呼び出してTODOリストのデータを取得します。

```typescript
const todos: Todo[] = await getData();
```

取得したデータ（todos）は、map関数で展開されて表示しています。

```html
return (
    <>
      <h1>Todos</h1>
      {todos.map((todo) => (
        <div key={todo.title}>{todo.title}</div>
      ))}
      <Link href="/">Home</Link>
    </>
  );
```

# 学んだこと

最初の状態は「何から始めればいいの？」で手が止まってしまいましたが、「Next.js API」で検索しながら必要な知識を補いながら、進めていました。APIの実装に初挑戦し、以下学んだことを書きます。

### フォルダ構成の理解

このプロジェクトでは、Next.jsの pages ディレクトリ内に api フォルダを作成しました。このフォルダ内にJavaScriptファイルを配置することで、APIのデータを定義することができます。この設計により、<font color="red">**ファイルパスが自動的にエンドポイントのURLに変換される**</font>ため、APIの管理が非常に効率的になることを学びました。

### 非同期処理の理解
非同期処理に関して、今回のプロジェクトで完全に理解するには至りませんでしたが、<font color="red">**fetchを使用して特定のURLからデータを取得する**</font>基本的な方法について学ぶことができました。
# 終わりに

簡単なTODOアプリのAPIを自分で実装することにより、APIに関する理解が深まりました。今回はpagesディレクトリを使用したフォルダ構成にしました。次回は、appルーターを導入してAPIの設計がどのように変わるのかを試してみることが楽しみです。