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

公開:2021/02/09
更新:2021/02/09
3 min読了の目安(約3100字TECH技術記事

◯◯ 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での開発を支えてくれそうです。