Koaあれこれ
July 23, 2021 -body parser
https://github.com/koajs/bodyparser
json, form , text , xml での body をパースするのに必要。
import Koa from 'koa';
import bodyParser from 'koa-bodyparser';
const app = new Koa();
app.use(bodyParser());
app.use(async (ctx) => {
  // request.body に送信されたデータが入る。
  // 空の場合は`{}` となる
  console.log(ctx.request.body);
});
TypeScript で body の型を定義する場合は generics を付ける
interface UserRequestBody {
  name: string;
  age: number;
}
app.use(async (ctx) => {
  const user = <UserRequestBody>ctx.request.body;
  console.log(user.name);
});
エラーのハンドリングについて
https://github.com/koajs/koa/wiki/Error-Handling
app.use(async (ctx, next) => {
  try {
    await next();
  } catch (err) {
    ctx.status = err.status || 500;
    ctx.body = err.message;
    ctx.app.emit('error', err, ctx);
  }
});
app.on('error', (err, ctx) => {
  /*
   * 全体のエラーを管理する
   * console.log,errorをここで書いたり、ログに書き込んだりする
   * リクエストの内容は引数のctx.requestで確認できる
   */
});
ctx.throw を利用することで上記同様の処理ができる
const err = new Error('name required');
err.status = 400;
err.expose = true;
throw err;
↓
ctx.throw(400, 'name required');
※ ctx.throw を使うと json は返せない(文字列のみ)、なので、エラー時に json を返したい場合は下記のように手動で書く必要がある。またはそれ用のライブラリを使う。
ctx.type = 'json';
ctx.status = 500;
const message = 'error occured';
ctx.body = {
  status: 'error',
  message
};
ctx.app.emit('error', new Error(message), ctx);
CORS
@koa/cors を使った複数ドメインへの CORS の制御の方法
import cors from '@koa/cors';
const isDev = process.env.NODE_ENV === 'development';
// 有効なoriginを定義
let validOrigins: string[] = [];
if (!isDev) {
  validOrigins = ['yourdomain.com', 'yourdomain2.io'];
}
const verifyOrigin = ({ headers: { origin = '' } }: Koa.Context) => {
  // 指定がない場合は全部許可(主に開発向け)
  if (validOrigins.length === 0) {
    return '*';
  }
  const valid = validOrigins.some((o) => origin.indexOf(o) > -1);
  if (!valid) return '';
  return origin;
};
app.use(cors({ origin: verifyOrigin }));
logging
リクエストのログは koa-logger 、それ以外の logging は pino を利用するようにしました。
logger.ts
import pino from 'pino';
const isDev = process.env.NODE_ENV === 'development';
export const logger = pino({
  level: process.env.LOG_LEVEL || isDev ? 'debug' : 'info',
  prettyPrint: {
    colorize: true,
    translateTime: `SYS:yyyy-mm-dd HH:MM:ssTT Z`,
    crlf: true
  }
});
import { logger } from './logger';
// Koa loggerのメッセージをpinoへ流す
app.use(
  koaLogger({
    transporter: (str) => logger.info(str)
  })
);
// 通常のlogはlogger.info等で呼び出す
logger.info('ログです');
このように表示されます
