🦁

Nest.js で typeorm session ストアを利用する

2022/03/19に公開

Nest.js x Session

Nest.js における session の機能は、express-session を利用して実装可能です。

$ npm i express-session
$ npm i -D @types/express-session

https://docs.nestjs.com/techniques/session

インストールした express-sessionmain.ts で以下のように記述します。

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as session from 'express-session';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  app.use(
      session({
        secret: 'my-secret',
        resave: false,
        saveUninitialized: false,
        cookie: {
          maxAge: 7 * 24 * 60 * 60 * 1000, // 7days
        }
      }),
  );
  await app.listen(process.env.PORT || 3000);
}
bootstrap();

session 関数には様々なオプションを指定可能です。

  • secret : セッション ID に署名をつける際の鍵文字列
  • resave : セッションデータに変更がなかったとしても セッションのデータを上書き更新します。
  • saveUninitialized : 初期化されていないセッションも store に保存します。
  • cookie : クッキーに関連する様々なオプションを指定します。

express session の default store

express session の 標準の store は、開発用です。
公式のリポジトリでも以下のように記載されています。

Warning The default server-side session storage, MemoryStore, is purposely not designed for a production environment. It will leak memory under most conditions, does not scale past a single process, and is meant for debugging and developing.

https://github.com/expressjs/session#readme

production で session を利用する際には、何かしらの Session Store 機構を導入する必要があります。

TypeOrm Store を利用する

session store として一番使いやすいのが typeorm ベースの database store かと思います。

まずは、必要なモジュールをインストールします。

$ npm i connect-typeorm

typeorm の エンティティを以下のように作成して、テーブルを作成しましょう。

import {Entity, Column, Index, PrimaryColumn} from "typeorm";
import { ISession } from "connect-typeorm";

@Entity("t_session")
export class Session implements ISession {
    @Index()
    @Column("bigint")
    public expiredAt = Date.now();

    @PrimaryColumn("varchar", { length: 255 })
    public id = "";

    @Column("text")
    public json = "";
}

作成したエンティティをベースに main.ts を以下のように記述します。


import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as session from 'express-session';
import {TypeormStore} from "connect-typeorm";
import {Session} from "./entities/session.entity";
import {getConnection} from "typeorm";

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  const sessionRepository = getConnection().manager.getRepository(Session);
  app.use(
      session({
        secret: 'my-secret',
        resave: false,
        saveUninitialized: false,
        cookie: {
          maxAge: 7 * 24 * 60 * 60 * 1000,
        },
        store: new TypeormStore().connect(sessionRepository),
      }),
  );
  await app.listen(process.env.PORT || 3000);
}
bootstrap();

TypeormStore には、第一引数にオプションで以下のような値を渡すことが可能です。

  • cleanupLimit : セッションが新しくなったときに、有効期限が切れたセッションをどの程度保持するか。default は 0 で、調査目的で遡及的に遡るニーズがあれば数値で世代を指定します。
  • limitSubquery : 一つのクエリで Session の select delete 両方を実施します。 defaults は true ですが、MariaDB などではサブクエリにおける limit 句が利用できない都合から、cleanupLimit を利用する際には false を指定する必要があります。
  • ttl : セッションの有効期限秒(time to live)。デフォルトは session.maxAge で maxAge がない場合 1日となります。

その他の Store

DB ではなく redis を session store として利用する場合には connect-redis が利用可能です。

https://www.npmjs.com/package/connect-redis

その他利用可能な store 情報の一覧は GitHub から確認できます。

https://github.com/expressjs/session#compatible-session-stores

Discussion