❄️

schematsでDBスキーマからTypeScript型定義を手に入れる

2021/02/09に公開

◯◯ to ts

昨今、さまざまな情報から TypeScript に変換することが可能です。

こういった TypeScript のコード生成ツールを利用することで、バックエンドの変更によって影響を受けるフロントエンド側の箇所を静的に検知できるなどの恩恵を受けることができます。

私も実際 GraphQL Code Generator を仕事で使いましたが、最高便利でした。

DB のスキーマ変更にも追従したい

上記に挙げたものは、バックエンド ⇆ フロントエンドや、BFF⇄API という関係性においてはとても強力な効果を発揮します。

ここで、さらに後方に控えるデータベースのスキーマ変更についても何らかの方法で追従できれば、スキーマ変更からフロントエンドの型定義まで一貫して静的に検知することが可能になり、とてもハッピーになれそうです。

また、サービス規模によっては、単純に DB のテーブルとほぼ同じデータ構造のまま REST で返すケースもあるのではないでしょうか。そういった場合、DB スキーマの変更はダイレクトに API の IF に影響することになります。

最近だと Prisma(https://www.prisma.io/)を使うことでスキーマに紐づく形でDBアクセスが可能にはなりますが、専用API経由になるため、純粋に型定義だけ取り出す場合には一苦労しそうです。(未検証です)

schemats

というわけで、 schemats の紹介です。

https://github.com/SweetIQ/schemats

schemats を利用することで、サクっと PostgreSQL または MySQL の DB スキーマをもとに TypeScript 型定義を出力することができます。

実際やってみる

※2020/2/9 現在、PostgreSQL 12.x と Node 4.x を組み合わせた場合にはエラーとなるようです。ご注意ください。
https://github.com/SweetIQ/schemats/issues/120

事前準備

まずは雑に Docker で PostgreSQL を立ち上げて準備します。

 docker run --rm -d \
    -p 5432:5432 \
    -v pgsql:/var/lib/postgresql/data \
    -e POSTGRES_HOST_AUTH_METHOD=trust \
    postgres:latest

それっぽいテーブルを作成します。

table.sql
CREATE TABLE users (
  id INTEGER,
  name VARCHAR(100),
  admin BOOLEAN
);

CREATE TABLE articles (
  id INTEGER,
  title VARCHAR(255),
  user_id INTEGER
);
psql -h localhost -p 5432 -U postgres -f table.sql

schemats の実行

あとは、schemats の README に沿ってコマンドを実行するだけです。

インストールして..

npm install -g schemats

実行します

schemats generate -c postgres://postgres@localhost/postgres -s public -o db.ts

すると、 指定した db.ts というファイル名でスキーマに対応した型定義が出力されているのがわかります。

db.ts
/* tslint:disable */


/**
 * AUTO-GENERATED FILE @ 2021-02-09 22:40:53 - DO NOT EDIT!
 *
 * This file was automatically generated by schemats v.3.0.3
 * $ schemats generate -c postgres://username:password@localhost/postgres -t articles -t users -s public
 *
 */


export namespace articlesFields {
    export type id = number | null;
    export type title = string | null;
    export type user_id = number | null;

}

export interface articles {
    id: articlesFields.id;
    title: articlesFields.title;
    user_id: articlesFields.user_id;

}

export namespace usersFields {
    export type id = number | null;
    export type name = string | null;
    export type admin = boolean | null;

}

export interface users {
    id: usersFields.id;
    name: usersFields.name;
    admin: usersFields.admin;

}

簡単ですね。

ちなみにオプションを付与することで

  • -C : キャメルケースで出力
  • -t : 出力するテーブルを絞る

といったことも可能です。

また、設定を JSON ファイルに定義してそれを指定して実行することもできるので、絞りこむテーブルが多い場合などには便利かもしれません。

実際どうか

今後 Prisma が採用されるケースが増えた場合には .prisma を正とする運用になることもありそうですが、その未来がくるまでにはもう少し時間がかかりそうです。

既存 DB を元に簡単に型定義を出力できることが有用なケースは、現実にはそれなりにあるのではないかと思います。

DB とほぼ同様の構造で REST API でデータを返している場合などにも使えるかもしれませんが、その場合、そもそも DB 構造がフロントまでそのまま流れることの是非は検討すべきかと思いますし、万が一 SourceMap などが漏洩した場合、DB スキーマ情報がそのまま漏れてしまうことになる点にはかなり慎重になる必要があるかと思います。

とはいえ、使い所を見極めればとても強力に TypeScript での開発を支えてくれそうです。

GitHubで編集を提案

Discussion