【Node.js活用講座】JSON Server(Express.js)でルーター内部でasync/awaitの処理をさせてみたときの話


2022/05/02

JSON-Serverで同期処理を行わせる際のテクニックを紹介します。

なお、JSON-Serverの使い方・実装の基本は前回の記事を参考にしてください。


Express/JSON-Serverで使える即席のasync/await対応

以下のようにユーティリティメソッドを独立したモジュールとしてルーターのラップ関数を作成しておきます。

            
            import { Request, Response, NextFunction, RequestHandler } from 'express';

type RequestHandler$ = {
    (req: Request, res: Response, next: NextFunction): Promise<any>
};

export function pipe$(asyncFunc: RequestHandler$): RequestHandler {
    return (req: Request, res: Response, next: NextFunction) => asyncFunc(req, res, next).catch(next);
}
        
と、あとはこの関数を一度パイプすることで、Expressルーターにasync/awaitを組み込むことができるようになります。

これでも通常のPromiseのrejectやthrowで投げたerrorもcatchすることができます。

利用時は少し紛らわしいので、以下に使用例を挙げておきます。

ユースケース①〜直接パイプの中でasync関数をラップする

では先程のpipe$関数を使って、async関数をラップして使ってみます。

            
            import jsonServer from 'json-server';
import { Request, Response } from 'express';
import { echo, echo$ } from './middleware/echo.handler';
import { pipe$ } from './src/asyncPipe';

const endpoint = 'http://localhost:3000';
const server = jsonServer.create();
const router = jsonServer.router'db.json');
const middlewares = jsonServer.defaults();

server.use(middlewares);

//👇ミドルウェアとしてasync関数が利用できる
server.get('/user/:id', pipe$(async (req: Request, res: Response) => {
    const id = req.params.id;
    if (!id) { throw new Error('ID is Not Found!'); }
    const user = {name: 'John', id};
    res.status(200).json(user);
}));

server.use(router);
server.listen(3000, () => { console.log(`JSON Server is now running at ${endpoint}!`); });
        

ユースケース②〜外で定義したasync関数を使う

もう少し突っ込んだ使い方として、pipe$メソッドの外に独立した関数として払い出してみます。

            
            import jsonServer from 'json-server';
import { Request, Response } from 'express';
import { echo, echo$ } from './middleware/echo.handler';
import { pipe$ } from './src/asyncPipe';

const endpoint = 'http://localhost:3000';
const server = jsonServer.create();
const router = jsonServer.router'db.json');
const middlewares = jsonServer.defaults();

server.use(middlewares);

//👇外に出したasync関数
async function getWho(req: Request, res: Response) {
    const id = req.params.id;
    if (!id) { throw new Error('ID is Not Found!'); }
    const user = {name: 'John', id};
    res.status(200).json(user);
}

server.get('/user/:id', pipe$(getWho));

server.use(router);
server.listen(3000, () => { console.log(`JSON Server is now running at ${endpoint}!`); });
        

ユースケース③〜外部モジュールで定義したasync関数を使う

最後に別のリソースから定義したモジュールとしても使えるようにして、async関数を呼び出します。

            
            import { Request, Response, RequestHandler } from 'express';

export async function getWho(req: Request, res: Response): Promise<any> {
    const id = req.params.id;
    if (!id) { throw new Error('ID is Not Found!'); }
    const user = {name: 'John', id};
    res.status(200).json(user);
};
        
あとはメインコードから呼び出して利用すると、よりスッキリとします。

            
            import jsonServer from 'json-server';
import { pipe$ } from './src/asyncPipe';
import { getWho } from './src/util';

const endpoint = 'http://localhost:3000';
const server = jsonServer.create();
const router = jsonServer.router'db.json');
const middlewares = jsonServer.defaults();

server.use(middlewares);

//👇外部モジュールからasync関数を呼び出し
server.get('/user/:id', pipe$(getWho));

server.use(router);
server.listen(3000, () => { console.log(`JSON Server is now running at ${endpoint}!`); });
        

以上、ラップ関数にパイプすることで、Expressのルーターをasync/await対応する方法の話でした。


参考サイト

【Express.js】非同期処理の個人的ベストプラクティス (async/await)

記事を書いた人

記事の担当:taconocat

ナンデモ系エンジニア

主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。