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