このレッスンのロックを解除するには、まず「レッスン3:ルーティング、コントローラー、プロジェクト構成」を完了してください。前のレッスンに戻る

はじめに

すべての実用的なAPIは、クライアントからデータを受信する必要があります — URLに含まれるユーザーID、クエリ文字列のフィルターオプション、フォームデータを含むJSONボディなど。CRUDエンドポイントを構築する前に、Expressが受信データの各部分をどこに配置し、それを確実に読み取る方法を知っておく必要があります。

このレッスンでは、3つの主要な入力ソース — URLパラメータ、クエリ文字列、リクエストボディ — を取り上げ、それらすべてを単純なリソース用の完全なCRUDエンドポイントセットで活用します。

入力の読み取り:パラメータ、クエリ文字列、ボディ

Expressは受信リクエストデータを、リクエストオブジェクト上の3つの異なるオブジェクトに解析します。

URLパラメータはパスの名前付きセグメントです。ルート定義でコロンを使用して宣言し、Expressはそれらをreq.paramsで利用できるようにします。

javascript
app.get('/users/:id', (req, res) => {
const userId = req.params.id;
res.json({ requested: userId });
});

クエリ文字列はURLの疑問符の後に表示されます。例:`/users?role=admin&limit=10` の形式です。Expressはこれらを自動的にreq.queryに解析します。

javascript
app.get('/users', (req, res) => {
const { role, limit } = req.query;
res.json({ role, limit });
});

リクエストボディはクライアントから送信される構造化データを運びます。多くの場合JSON形式です。Expressはデフォルトではボディを解析しないため、ルートより前に組み込みのexpress.json()ミドルウェアを登録する必要があります。

javascript
const express = require('express');
const app = express();
app.use(express.json());

このミドルウェアが配置されると、POSTやPUTのペイロードがreq.bodyで利用可能になります。

受信HTTPリクエストが3つのパスに分岐するフローチャート:URLパラメータはreq.paramsへ、クエリ文字列はreq.queryへ、JSONボディはexpress.json()ミドルウェアを介してreq.bodyへ

完全なCRUD APIの構築

ルーティングの仕組みに焦点を当てるため、以下の例ではデータストアとしてインメモリ配列を使用しています。実際のプロジェクトでは、配列の操作をデータベース呼び出しに置き換えることになります。

データとID生成用のヘルパーから始めましょう:

javascript
let users = [
{ id: 1, name: 'Alice', role: 'admin' },
{ id: 2, name: 'Bob', role: 'user' },
];
let nextId = 3;

Create — POST /users はボディを読み取り、新しいレコードをプッシュします:

javascript
app.post('/users', (req, res) => {
const { name, role } = req.body;
if (!name || !role) {
return res.status(400).json({ error: 'name and role are required' });
}
const newUser = { id: nextId++, name, role };
users.push(newUser);
res.status(201).json(newUser);
});

Read all — GET /users はクエリ文字列によるroleでのオプションのフィルタリングをサポートします:

javascript
app.get('/users', (req, res) => {
const { role } = req.query;
const result = role ? users.filter(u => u.role === role) : users;
res.json(result);
});

Read one — GET /users/:id は req.params を使用して単一のレコードを検索します:

javascript
app.get('/users/:id', (req, res) => {
const user = users.find(u => u.id === Number(req.params.id));
if (!user) return res.status(404).json({ error: 'User not found' });
res.json(user);
});

Update — PUT /users/:id はパラメータ(どのレコードか)とボディ(新しい値)を組み合わせます:

javascript
app.put('/users/:id', (req, res) => {
const index = users.findIndex(u => u.id === Number(req.params.id));
if (index === -1) return res.status(404).json({ error: 'User not found' });
const { name, role } = req.body;
users[index] = { ...users[index], ...(name && { name }), ...(role && { role }) };
res.json(users[index]);
});

Delete — DELETE /users/:id はレコードを削除し、204 No Contentを返します:

javascript
app.delete('/users/:id', (req, res) => {
const index = users.findIndex(u => u.id === Number(req.params.id));
if (index === -1) return res.status(404).json({ error: 'User not found' });
users.splice(index, 1);
res.status(204).send();
});
HTTPメソッドとパスをCRUD操作に対応付けた表形式の図:POST /users → Create、GET /users → Read All、GET /users/:id → Read One、PUT /users/:id → Update、DELETE /users/:id → Delete

よくある間違い

express.json()を忘れることは、初心者にとって最も頻繁な混乱の原因です。req.bodyがundefinedの場合、ミドルウェアが登録されているか、クライアントがContent-Type: application/jsonヘッダーを送信しているかを確認してください。

req.params.idを比較する前に数値に変換しないことも、別の微妙なバグです。ルートパラメータは常に文字列です。文字列の「1」と数値の1を厳密等価演算子で比較すると常にfalseになるため、findやfindIndexの呼び出しではすべてのレコードが静かにミスされます。

レスポンスを送信した後にデータを返すと、Expressで「headers already sent」エラーが発生します。条件文の中でres呼び出しの前に必ずreturnを使用してください。上記の例で示されている通りです。

まとめ

Expressは受信リクエストデータを3つのオブジェクトに分割します:URLセグメント用のreq.params、クエリ文字列用のreq.query、解析されたJSONペイロード用のreq.body。express.json()ミドルウェアを登録することでボディの解析が有効になります。3つの入力ソースを理解した上で、標準的なCRUDエンドポイントを構築するには、HTTPメソッドとステータスコードを正しいデータ操作に対応付けるだけです — POSTと201を作成に、GETを読み取りに、PUTを更新に、DELETEと204を削除に。

レッスンの練習

レッスンのチェックポイント

学んだ内容を復習し、回答へのフィードバックを受けましょう。

0/1
回答済み · 0/1