この記事でわかること
どうも、バックエンド一本で飯を食ってきた俺だ。フロントの華やかな世界には目もくれず、ひたすらサーバーサイドで生きてきた。今日はそんな俺が、API構築の「入門」を叩き込む。
この記事を読むと、次のことがわかる。
- そもそもAPIとは何か、なぜ必要なのか
- REST APIの設計で押さえるべき考え方
- 実際に動くAPIをコードで書く方法(Node.js/Express例)
- 現場で恥をかかないための設計のコツ
難しい話は最小限にする。まずは手を動かして「作れる」ようになろうじゃないか。
そもそもAPIって何なんだ
API(Application Programming Interface)ってのは、ソフトウェア同士が会話するための「窓口」だ。
たとえば天気アプリ。あれは自前で気象観測してるわけじゃない。気象データを持ってるサーバーに「東京の天気くれ」とお願いして、返ってきたデータを画面に出してるだけだ。この「お願いする窓口」がAPIってわけだな。
Webの世界で今主流なのがHTTPを使った Web API、その中でも REST という設計スタイルが広く使われている。
RESTの基本思想を叩き込む
RESTってのは堅苦しいルールブックじゃない。ざっくり言えば「リソース(データ)を、URLで表して、HTTPメソッドで操作する」って考え方だ。
リソースは名詞で表す
URLはやることじゃなく「対象物」を表す。ここを間違える新人が多い。
| 良い例 | 悪い例 |
|---|---|
/users | /getUsers |
/users/1 | /getUserById?id=1 |
/articles/5/comments | /fetchArticleComments |
動詞をURLに入れるな。動詞はHTTPメソッドが担当するんだ。
HTTPメソッドで操作を表す
「何をするか」はメソッドで表現する。この対応は暗記しておけ。
| メソッド | 意味 | 例 |
|---|---|---|
| GET | 取得 | GET /users 一覧取得 |
| POST | 作成 | POST /users 新規登録 |
| PUT | 更新(全体) | PUT /users/1 |
| PATCH | 更新(一部) | PATCH /users/1 |
| DELETE | 削除 | DELETE /users/1 |
ステータスコードで結果を伝える
返事のときは適切なステータスコードを使え。「とりあえず200返しとけ」は素人のやることだ。
- 200 OK:成功
- 201 Created:作成成功
- 400 Bad Request:リクエストが不正
- 401 Unauthorized:認証が必要
- 404 Not Found:対象が存在しない
- 500 Internal Server Error:サーバー側の落ち度
設計から始めるのが筋ってもんだ
いきなりコードを書くな。まず「どんなリソースがあって、どんな操作を提供するか」を紙でもテキストでも書き出せ。
今回はシンプルな「ユーザー管理API」を作るとしよう。設計はこうだ。
GET /users ユーザー一覧を取得
GET /users/:id 特定ユーザーを取得
POST /users ユーザーを新規作成
PUT /users/:id ユーザー情報を更新
DELETE /users/:id ユーザーを削除
この5つが揃えば、いわゆるCRUD(Create/Read/Update/Delete)の基本形が完成する。設計が決まればコードは自然と書ける。
実際にコードを書くぞ
今回はNode.jsとExpressで書く。理由は単純、記述量が少なくて入門にちょうどいいからだ。
まずはプロジェクトの準備。
mkdir user-api && cd user-api
npm init -y
npm install express
次に本体だ。データベースは入門なので使わず、メモリ上の配列で代用する。
const express = require('express');
const app = express();
// JSONのリクエストボディを読めるようにする
app.use(express.json());
// 仮のデータストア
let users = [
{ id: 1, name: '田中', email: '[email protected]' },
{ id: 2, name: '佐藤', email: '[email protected]' },
];
let nextId = 3;
// 一覧取得
app.get('/users', (req, res) => {
res.json(users);
});
// 個別取得
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: 'ユーザーが見つかりません' });
}
res.json(user);
});
// 新規作成
app.post('/users', (req, res) => {
const { name, email } = req.body;
if (!name || !email) {
return res.status(400).json({ error: 'nameとemailは必須です' });
}
const user = { id: nextId++, name, email };
users.push(user);
res.status(201).json(user);
});
// 更新
app.put('/users/:id', (req, res) => {
const user = users.find(u => u.id === Number(req.params.id));
if (!user) {
return res.status(404).json({ error: 'ユーザーが見つかりません' });
}
const { name, email } = req.body;
if (name) user.name = name;
if (email) user.email = email;
res.json(user);
});
// 削除
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: 'ユーザーが見つかりません' });
}
users.splice(index, 1);
res.status(204).send();
});
app.listen(3000, () => {
console.log('APIサーバー起動: http://localhost:3000');
});
起動はこれだけだ。
node index.js
動作を確認する
サーバーが立ち上がったら、curl で叩いてみろ。
# 一覧取得
curl http://localhost:3000/users
# 新規作成
curl -X POST http://localhost:3000/users \
-H 'Content-Type: application/json' \
-d '{"name":"鈴木","email":"[email protected]"}'
# 削除
curl -X DELETE http://localhost:3000/users/1
ちゃんとJSONが返ってきたか? おめでとう、それがもうAPIだ。難しくないだろう。
現場で恥をかかないためのコツ
動くものは作れた。だが「動く」と「使える」は別モノだ。最後に、俺が現場で口酸っぱく言ってることを伝えておく。
- バリデーションを怠るな。ユーザー入力は基本的に信用するな。おかしなデータは400で門前払いしろ。
- エラーレスポンスの形式を統一しろ。
{ "error": "..." }のように一貫させると、使う側が楽になる。 - ステータスコードを正しく使え。全部200で返すAPIは、使う側を地獄に落とす。
- 認証・認可を忘れるな。今回は省いたが、本番では誰でも削除できるAPIなんて論外だ。トークン認証などを入れろ。
- ドキュメントを残せ。OpenAPI(Swagger)を使えば、仕様書と動作確認画面が同時に手に入る。
このあたりは一般論として、どの言語・フレームワークでも共通する考え方だ。言語が変わっても設計思想は生き続ける。
まとめ
今日の内容を振り返るぞ。
- APIはソフトウェア同士の会話の窓口
- RESTは「リソースをURLで表し、HTTPメソッドで操作する」考え方
- URLは名詞、操作はメソッド、結果はステータスコードで表す
- 設計を先に固めてから実装すると迷わない
- 動くだけでなく、バリデーション・エラー処理・認証まで気を配れ
APIは一度作れるようになると、世界が広がる。フロントとつなぐのも、外部サービスと連携するのも、全部この延長線上だ。まずは手元でこのユーザーAPIをいじり倒せ。壊して直して、それが一番身につく。
それじゃあな、達者でコードを書けよ。