schematsでDBスキーマからTypeScript型定義を手に入れる
◯◯ to ts
昨今、さまざまな情報からTypeScriptに変換することが可能です。
- GraphQL から
→ GraphQL Code Generator (https://graphql-code-generator.com/) - Protocol buffers から
→ protobuf-ts (https://github.com/timostamm/protobuf-ts) - OpenAPI から
→ openapi-typescript (https://github.com/drwpow/openapi-typescript)
こういったTypeScriptのコード生成ツールを利用することで、バックエンドの変更によって影響を受けるフロントエンド側の箇所を静的に検知できるなどの恩恵を受けることができます。
私も実際 GraphQL Code Generator を仕事で使いましたが、最高便利でした。
DBのスキーマ変更にも追従したい
上記に挙げたものは、バックエンド⇆フロントエンドや、BFF⇄APIという関係性においてはとても強力な効果を発揮します。
ここで、さらに後方に控えるデータベースのスキーマ変更についても何らかの方法で追従できれば、スキーマ変更からフロントエンドの型定義まで一貫して静的に検知することが可能になり、とてもハッピーになれそうです。
また、サービス規模によっては、単純にDBのテーブルとほぼ同じデータ構造のままRESTで返すケースもあるのではないでしょうか。そういった場合、DBスキーマの変更はダイレクトにAPIのIFに影響することになります。
最近だとPrisma(https://www.prisma.io/)を使うことでスキーマに紐づく形でDBアクセスが可能にはなりますが、専用API経由になるため、純粋に型定義だけ取り出す場合には一苦労しそうです。(未検証です)
schemats
というわけで、 schemats
の紹介です。
schemats
を利用することで、サクっとPostgreSQLまたはMySQLのDBスキーマをもとにTypeScript型定義を出力することができます。
実際やってみる
※2020/2/9現在、PostgreSQL 12.x と Node 4.x を組み合わせた場合にはエラーとなるようです。ご注意ください。
事前準備
まずは雑にDockerでPostgreSQLを立ち上げて準備します。
docker run --rm -d \
-p 5432:5432 \
-v pgsql:/var/lib/postgresql/data \
-e POSTGRES_HOST_AUTH_METHOD=trust \
postgres:latest
それっぽいテーブルを作成します。
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
というファイル名でスキーマに対応した型定義が出力されているのがわかります。
/* 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での開発を支えてくれそうです。