REST APIって何？簡単なReact/Node.jsアプリで作って理解する・その2（バックエンド編）

# 前回のおさらい

前回は初心者向けにREST APIとは何か、簡単に解説しました。今回は実際にREST APIをNode.jsを使って作成します。

「JSON Serverを使って、ローカルでTodoアプリを動かす」という簡単な学習項目になりますが、CRUD操作（Create, Read, Update, Delete）の基本的な書き方になるので、Node.jsを学習中の方はぜひ参考にしてください！

**前回の記事URLです。**
https://qiita.com/Shuheitkhs/items/7bd3dcbd5fc487afc5c9

# 今回の開発環境の準備

今回の開発環境を準備していきます。

## 開発環境の確認

まずは、Node.jsとnpmがインストールされていることを確認してください。ターミナルで以下のコマンドを実行し、バージョンが表示されればOKです。

```bash
node -v
npm -v
```

## プロジェクトディレクトリの作成と初期化

次にプロジェクトのディレクトリを作成し、初期化、その他必要なパッケージのインストールを進めていきます。

```bash

# プロジェクトディレクトリの作成と移動

mkdir my-backend-project
cd my-backend-project

# npmを初期化してpackage.jsonを作成
npm init -y  # -yオプションでデフォルト設定を自動承認

# Expressのインストール
npm install express

# TypeScriptと型定義のインストール
npm install --save-dev typescript @types/node @types/express

# TypeScriptの初期設定ファイルを生成
npx tsc --init  # tsconfig.jsonを作成

# 開発ツールのインストール（自動再起動のためのnodemon）
npm install --save-dev nodemon ts-node

# srcディレクトリの作成とエントリーポイントのファイルを作成
mkdir src
touch src/server.ts  

# 必要なミドルウェアのインストール（CORSとボディパーサー）
npm install cors body-parser
npm install --save-dev @types/cors @types/body-parser  
```

### json-serverとは
JSONファイルをデータベースのように使えるモックAPIサーバーを簡単に作れます。今回はREST APIの作成が目的なので、データベースは簡易なJSON serverを使用します。

### expressとは
Node.jsで最も人気のあるフレームワークです。ルーティング、ミドルウェア、静的ファイル配信など、Webアプリケーションに必要な基本機能を簡単に実装できます。
### corsとは
異なるドメイン間でのデータのやり取りを可能にするミドルウェアです。今回のように、フロントエンドとバックエンドが異なるドメインにある場合は必要になります。
### body-parserとは
クライアントから送られてくるリクエストのボディ（JSON形式やフォームデータなど）を自動的にパースしてJavaScriptのオブジェクトに変換してくれます。

## 完成形コード

バックエンドの完成形のコードは以下のリポジトリにありますので、エラーなどが出たときは参考にしてみてください。

https://github.com/Shuheitkhs/todo-api

# REST API の作成

開発準備ができたら早速、REST APIを記載していきましょう！今回はserver.tsに記載CRUD操作を記載していく形にします。

## GET メソッド（Read）の作成

まずはTodoの一覧を取得するためのgetメソッドを作成していきます。

```server.ts
import express, { Request, Response } from "express";
import cors from "cors";
import bodyParser from "body-parser";

const app = express();
const PORT = 4000;
// ミドルウェアの設定
app.use(cors());
app.use(bodyParser.json());

// 型の設定todo
type Todo = { id: string; text: string; completed: boolean };
let todos: Todo[] = [];

// getですべてのtodoを取得
app.get("/todos", (req: Request, res: Response) => {
  res.json(todos);
});
```
前半部分は必要なパッケージのインストールやインストールしたミドルウェアの設定、型の定義になります。

```server.ts
// getですべてのtodoを取得
app.get("/todos", (req: Request, res: Response) => {
  // JSON形式でtodosをクライアントに返す
  res.json(todos);
});
```

上記のコードを読み取ると、前回紹介したREST APIの特徴を持っていることがわかります。

> REST APIの特徴
> 1. リソースごとにURLを定義する
> 2. メソッドでリソースへの処理を定義する
>3. JSONでデータをやりとりする

### リソースごとにURLを定義する

第一引数に`"/todos"`が記載されており、こちらが今回リクエストを送る先のエンドポイントですね！

### メソッドでリソースへの処理を定義する

`app.get`と記載されているようにgetメソッドでリソースへの処理を定義しています。

### JSONでデータをやりとりする

`res.json(todos)`このようにJSON形式でレスポンスを受けとっているのも確認できますね！

## POSTメソッド（Create）の作成

次に新しいTodoを作成するためのpostメソッドを作成していきます。

```server.ts
// createで新しいtodoの作成
app.post("/todos", (req: Request, res: Response) => {
  // 新しいTodoの定義
  const newTodo = {
    // 現在の日時を文字列にしてidに設定
    id: Date.now().toString(),
    // リクエストのbodyに記載されたテキストをtextに設定
    text: req.body.text,
    // 完了済みのタスクか、boolean型で設定
    completed: false,
  };
  // db.json内のtodosに新しいnewTodoを追加
  todos.push(newTodo);
  // 成功の場合201ステータスをクライアントに返す
  res.status(201).json(newTodo);
});
```

## PUTメソッド（Update）の作成

```server.ts
// PUTで更新
app.put("/todos/:id", (req: Request, res: Response) => {
  // 更新するtodoのidを、リクエストのパラメータから取得
  const todoId = req.params.id;
  // JSON server内のtodoからidが合致しているものを探す
  const matchTodo = todos.find((t) => t.id === todoId);
  // もし合致しているものがあればtodoを更新して、該当の新しいtodoをクライアントに返す
  if (matchTodo) {
    matchTodo.text = req.body.text ?? matchTodo.text;
    matchTodo.completed = req.body.completed ?? matchTodo.completed;
    res.json(matchTodo);
  } else {
    // 見つからない場合は404エラーをクライアントに返す
    res.status(404).json({ message: "Todo not found" });
  }
})
```

今までは`"/todos"`で記載されていたURLが今回は`"/todos/:id"`になっているのがわかりますね。

GETメソッドは全体のTodoを取得、POSTメソッドは新しいTodoを追加する処理でしたので、個別のidは必要なかったのですが、今回は特定のTodoひとつだけに更新の処理をしたいので、`:id`を記載して、更新したいTodoを絞り込みます。

## DELETEメソッド(Delete)の作成

```server.ts
// deleteで削除
app.delete("/todos/:id", (req: Request, res: Response) => {
  // 削除するtodoのidを、リクエストのパラメータから取得
  const todoId = req.params.id;
  // 削除したいtodo以外をtodosと定義し配列を作成
  todos = todos.filter((t) => t.id !== todoId);
  // 成功した場合204ステータスを返す（delete操作を行う場合の基本）
  res.status(204).send();
})
```
DELETEメソッドについても、PUTメソッドと同じように、特定のidを持つtodoにのみ処理を行うので、`"/todos/:id"`の記載が必要です。

## テストしてみる

一旦CRUD操作を行うREST APIが完成しましたので、簡単にテストしてみましょう！

拡張機能のREST Clientを使ってテストしてみます。

詳細な使い方は以下の記事を参考にしてください。

https://qiita.com/mgmgmogumi/items/61f0b896580d3e6db2bb

### 具体的な手順

1. 拡張機能のREST Clientをインストール
2. `.http`の拡張子を持つファイルを作成。今回は`test.http`
2. 以下のコードをコピーペーストして、画面上に出てくるSend Requestをクリック

```text.http
### Get all todos
GET http://localhost:4000/todos
Accept: application/json


### Create a new todo
POST http://localhost:4000/todos
Content-Type: application/json

{
  "id": "{{$timestamp}}",
  "text": "新しいタスクを追加",
  "completed": true
}

```

※今回はGETとPOSTメソッドのみのテストです。

![SCR-20241124-ocao.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3934698/906253bb-e205-fa78-d36c-95c7be2b69ae.png)

これでテストができます！

## 次回はフロントエンドとの繋ぎこみ

今回はREST APIを簡単に作ってみました。次回は今回作成したAPIを使って実際に動くアプリを作ってみましょう！