Node.jsでWeb APIサーバーを作るとき、もっとも広く使われているのがExpressです。標準のhttpモジュールでもサーバーは作れますが、ルーティングやJSONの処理を自分で書く必要があり、コードが煩雑になります。Expressを使えば、数行でルーティング付きのAPIサーバーが作れ、JSONの返却やリクエストボディの受け取りも簡単です。
この記事では、expressのインストールから、GET・POSTのルーティング、URLパラメータやクエリの取得、JSONボディの受け取り、ステータスコードの設定まで、最小限のAPIサーバーを実機で動かしながら作っていきます。実際にサーバーを起動し、各エンドポイントにリクエストを送って動作を確認しています。
npm install expressでインストールし、const app = express()で始めます。- ルーティングは
app.get("/path", (req, res) => {...})のように書きます。 - JSONを返すのは
res.json(データ)。配列もオブジェクトもそのまま渡せます。 - URLの
:idはreq.params.id、?sort=...はreq.query.sortで取れます。 - POSTのJSONボディを受け取るには
app.use(express.json())が必須です。 - ステータスコードは
res.status(201).json(...)のように指定します。
素のサーバーとの違いはhttpモジュールでWebサーバーを作る、インストールまわりはnpmとpackage.jsonの基礎、ポート番号などの環境変数はprocess完全ガイドもあわせて参考になります。
Expressとは(httpモジュールとの違い)
Expressは、Node.jsのWebアプリケーション用フレームワークです。標準のhttpモジュールだけでルーティングを実装すると、if (req.url === "/users" && req.method === "GET")のような分岐を延々と書くことになります。Expressは、このルーティングとリクエスト・レスポンス処理をすっきり書けるようにしてくれます。APIサーバーやWebサービスのほとんどがExpress(や類似のフレームワーク)の上に作られています。
インストールと最小サーバー
まずnpm install expressでExpressをインストールします。そして数行で、リクエストに応答する最小のサーバーが作れます。
# プロジェクトフォルダで実行 npm init -y npm install express
const express = require("express");
const app = express();
// "/" にアクセスが来たら文字列を返す
app.get("/", (req, res) => {
res.send("Hello Express");
});
// 3000番ポートで待ち受ける
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`listening on ${PORT}`);
});
node server.jsで起動し、ブラウザやcurlでhttp://localhost:3000/にアクセスするとHello Expressが返ります。実機でも、この最小サーバーが正しく起動し、応答することを確認しました。express()でアプリを作り、app.getでルートを定義し、app.listenでポートを指定して待ち受ける——この3ステップが基本です。process.env.PORTを使うと、環境変数でポートを変えられます。
ルーティング(GET)
URLごとに異なる処理をするのがルーティングです。app.get("/パス", ハンドラ)で、そのパスへのGETリクエストに応答します。JSONを返すにはres.json()を使います。
// 文字列を返す
app.get("/hello", (req, res) => {
res.send("こんにちは");
});
// JSON(配列)を返す
app.get("/api/users", (req, res) => {
res.json([
{ id: 1, name: "田中" },
{ id: 2, name: "鈴木" },
]);
});
実機でも、/api/usersにアクセスすると[{"id":1,"name":"田中"},{"id":2,"name":"鈴木"}]というJSONが返りました。res.json()に配列やオブジェクトを渡すだけで、自動的にJSON文字列に変換され、Content-Type: application/jsonも付きます。素のhttpモジュールではJSON.stringifyやヘッダー設定を自分で書く必要がありますが、Expressでは不要です。
URLパラメータとクエリ
URLの一部を変数として受け取るのがURLパラメータ(:id)、?key=valueの部分がクエリです。それぞれreq.params・req.queryで取得します。
// :id の部分を req.params.id で受け取る
app.get("/api/users/:id", (req, res) => {
const id = Number(req.params.id);
const sort = req.query.sort || "none"; // ?sort=name の部分
res.json({ id: id, sort: sort });
});
// 例: GET /api/users/5?sort=name
// → { "id": 5, "sort": "name" }
実機でも、/api/users/5?sort=nameにアクセスすると{"id":5,"sort":"name"}が返りました。:idのようにコロンを付けた部分がreq.paramsに入り、?sort=nameのようなクエリはreq.queryに入ります。注意点として、req.paramsやreq.queryの値はすべて文字列です。数値として使いたいときはNumber()で変換します。
JSONを受け取る(POST + express.json)
クライアントから送られたJSONデータを受け取るには、POSTのルートを作り、app.use(express.json())を必ず設定します。これが無いとreq.bodyが空になります。
const express = require("express");
const app = express();
// 【必須】これが無いと req.body が undefined になる
app.use(express.json());
app.post("/api/users", (req, res) => {
const newUser = req.body; // 送られたJSONがオブジェクトで入る
console.log(newUser); // { name: "佐藤" }
res.status(201).json({ created: newUser });
});
実機で確認したところ、app.use(express.json())を設定したうえで{"name":"佐藤"}をPOSTすると、req.bodyに{ name: "佐藤" }が正しく入り、{"created":{"name":"佐藤"}}がステータス201で返りました。この一行を忘れると、req.bodyがundefinedになり、送ったデータを受け取れません。「POSTしたのにデータが取れない」というトラブルの定番原因です。JSONを受け取るAPIでは、ルート定義より前にapp.use(express.json())を書いておきましょう。フォーム送信(application/x-www-form-urlencoded)を受け取る場合はexpress.urlencoded()を使います。
ステータスコードと404
レスポンスのHTTPステータスコードはres.status()で指定します。作成成功なら201、未検出なら404、というように使い分けます。どのルートにも一致しなかったリクエストの処理も書けます。
// 見つからなければ 404 を返す
app.get("/api/users/:id", (req, res) => {
const user = findUser(req.params.id); // 仮の検索関数
if (!user) {
return res.status(404).json({ error: "not found" });
}
res.json(user);
});
// どのルートにも一致しなかったとき(最後に置く)
app.use((req, res) => {
res.status(404).json({ error: "ページが見つかりません" });
});
実機でも、定義していないパス(/nope)にアクセスするとステータス404が返ることを確認しました。res.status(コード)に続けて.json()や.send()をつなげて書きます。すべてのルート定義の最後にapp.use(...)を置くと、どれにも一致しなかったリクエストをまとめて処理でき、独自の404レスポンスを返せます。なお、ifの中でreturn res.status(...)のようにreturnを付けるのは、その後の処理を実行させないためのよくある書き方です。
ミドルウェアの基礎
Expressの中心的な仕組みがミドルウェアです。すべてのリクエストの前に共通処理(ログ出力・認証チェックなど)を挟めます。app.use()で登録し、next()を呼ぶと次の処理に進みます。
// すべてのリクエストの前に実行される
app.use((req, res, next) => {
console.log(`${req.method} ${req.url}`); // 例: GET /api/users
next(); // これを呼ばないと先に進まない(リクエストが止まる)
});
// express.json() も実はミドルウェアの一種
ミドルウェアは(req, res, next)の3つの引数を取り、処理が終わったらnext()を呼んで次へ進めます。next()を呼び忘れると、リクエストがそこで止まり、レスポンスが返らずタイムアウトになります。先ほどのexpress.json()も、実は「リクエストボディを読んでJSONに変換し、req.bodyにセットしてnext()する」ミドルウェアです。認証・ログ・CORS対応など、共通処理はミドルウェアとして書くのがExpressの基本スタイルです。登録した順番に実行されるため、express.json()や共通ミドルウェアはルート定義より前に置くことを意識してください。
主なメソッドまとめ
Expressでよく使うメソッドをまとめます。
| 書き方 | 働き |
|---|---|
app.get(path, fn) |
GETリクエストのルート |
app.post(path, fn) |
POSTリクエストのルート |
res.json(data) |
JSONを返す |
res.status(code) |
ステータスコードを指定 |
req.params |
URLパラメータ(:id) |
req.query |
クエリ(?key=value) |
req.body |
POSTのボディ(要express.json()) |
app.use(fn) |
ミドルウェアの登録 |
よくある失敗
express.json()を忘れてreq.bodyが空
JSONボディを受け取るにはapp.use(express.json())が必須です。ルートより前に書きます。
req.paramsを数値だと思って使う
パラメータやクエリは文字列です。数値として使うならNumber()で変換します。
ミドルウェアでnext()を呼び忘れる
リクエストが止まってタイムアウトします。処理後にnext()を呼びます。
404処理を先に書いてしまう
app.useの総括的な処理は、すべてのルート定義の後に置きます。
res.jsonとres.sendを二重に呼ぶ
レスポンスは1回だけです。2回送ろうとするとエラーになります。
よくある質問
httpモジュール、実際にAPIを作るならExpressが向いています。Expressはルーティング・JSON処理・ミドルウェアが簡単に書け、コードが大幅に短くなります。多くの実務プロジェクトでExpress(や類似フレームワーク)が使われています。app.use(express.json())を設定していない可能性が高いです。JSONボディを受け取るには、ルート定義より前にこの一行が必要です。フォーム送信を受け取る場合はexpress.urlencoded({ extended: true })を使います。:idのようなURLパラメータはreq.params.id、?sort=nameのようなクエリはreq.query.sortで取得します。どちらも値は文字列なので、数値として使うときはNumber()で変換してください。(req, res, next)を引数に取り、ログ出力・認証・ボディ解析などを行ってnext()で次へ進めます。app.use()で登録し、登録順に実行されます。express.json()もミドルウェアの一種です。app.listen(ポート番号)で指定します。const PORT = process.env.PORT || 3000のように書くと、環境変数PORTがあればそれを、無ければ3000を使う、という柔軟な指定ができます。本番環境ではポートを環境変数で渡すのが一般的です。まとめ
npm install expressでインストールし、express()・app.get・app.listenで最小サーバーが作れます。- JSONは
res.json()で返し、ステータスはres.status()で指定します。 :idはreq.params、クエリはreq.query(どちらも文字列)。- POSTのJSONは
app.use(express.json())が必須です。 - 共通処理はミドルウェアで書き、
next()で次へ進めます。
Expressを使えば、わずか数行でルーティング付きのAPIサーバーが作れます。「res.jsonでJSONを返す」「express.json()でJSONを受け取る」「共通処理はミドルウェア」という基本を押さえれば、本格的なWeb APIへ自然に発展させていけます。まずは最小のサーバーを動かして、ルートを少しずつ増やしてみてください。

