ルートでasync/awaitを使い、サーバーを落とさずに非同期のエラーを処理しましょう。
このレッスンを Kodokon で開く本物のルートは、メモリ上の配列を返したりはしません。ファイルを読み、データベースに問い合わせ、他のAPIを呼び出します。これらの操作はすべて非同期です。async/awaitはJavaScript講座から知っていますね。サーバーの中できれいに使う方法を見ていきましょう。まず良い知らせです。ルート関数はasyncにできます。
import express from "express";
import { readFile } from "node:fs/promises";
const app = express();
app.get("/report", async (req, res) => {
const raw = await readFile("report.json", "utf8");
res.json(JSON.parse(raw));
});
app.listen(3000);このコードは動きます……report.jsonが存在する限りは。読み取りに失敗すると、プロミスは拒否され、Expressのバージョンによっては、リクエストが応答のないままになったり、エラーがログに漏れ出したりします。プロのルールはこうです。すべての非同期ルートは自分のエラーを処理する、try/catchとnext(error)を使って、です。
app.get("/report", async (req, res, next) => {
try {
const raw = await readFile("report.json", "utf8");
res.json(JSON.parse(raw));
} catch (error) {
next(error);
}
});next(error)は、エラーを一元化されたエラーハンドラーへ渡します。これは四つのパラメーターを持つミドルウェアで、すべてのルートより後ろに宣言します。エラーを記録し整形する場所が一つだけあること。それこそが、保守できるAPIを週末の趣味プロジェクトと分けるものです。
app.use((err, req, res, next) => {
console.error(err);
res.status(500).json({
error: "Internal server error"
});
});最後に身につけたい習慣は、並列処理です。二つのawaitで連鎖させた独立した二つの操作は、順番に一つずつ実行されます。Promise.allはそれらを同時に起動します。応答時間は、二つの合計ではなく、最も遅いものの時間になります。
async function fetchUsers() {
return [{ id: 1, name: "Ada" }];
}
async function fetchTasks() {
return [{ id: 1, title: "Review the code" }];
}
app.get("/dashboard", async (req, res, next) => {
try {
const [users, tasks] = await Promise.all([
fetchUsers(),
fetchTasks()
]);
res.json({ users, tasks });
} catch (error) {
next(error);
}
});asyncルートで、catchが捕まえたエラーをどうしますか?console.logで記録して先に進むnext(error)を呼び出してエラーハンドラーへ渡すawaitで連鎖させるPromise.allで同時に起動するsetTimeoutを使うerrを先頭にした四つのパラメーターのシグネチャによってerrorHandlerでなければならない関数名によって