この記事は、【 可茂IT塾 Advent Calendar 2023 】の4日目の記事です。
2023年頭に、長らく運用しているWebアプリケーションのアプリ版を新しく作るため、Flutterアプリのバックエンドアプリケーション(APIサーバー)を開発する業務を任せていただきました。
いわゆるBFF(Backend For Frontend)の開発です。
この開発を通じて学んだことを共有します。3記事のシリーズになっているので合わせて以下の記事をお読みください。
新しくAPIサーバーを構築するため、使用技術の選定などから開始しましたが、主にデータベースに関係する制約が強く以下のような状況がありました。
(スキーマから生成したER図。モザイクがかってますが、一部のテーブルを除いて外部キー制約が付けられていない設計なのが伝わると思います。)
このような状況の中で開発を進めるにあたり、NestJSというNode.jsのバックエンドフレームワークとPrismaというORMを採用して開発を進めました。
選定理由としては、私自身が今までにAPIサーバーを開発する経験が乏しかったので、得意な言語であるTypeScriptを用いてエコシステムや現行のコミュニティの活発さによる新鮮な情報の多さを開発に活用できる点を重視しました。
Prismaは、データベースのスキーマからデータモデルを生成することができます。この機能を活用することで、既存のデータベースを活用しながら、データモデルを作成することができました。
prisma db pull
のコマンドを実行することで、既存のデータベースからスキーマを生成することができます。
うれしいのは、スキーマを生成するのと一緒にテーブルの型定義も生成してくれることです。 これにより、既存のデータベースのスキーマからTypeScriptの型定義を生成することができました。
APIサーバーでのSQL操作は、参照系のクエリがほとんどでした。ので、データ取得部分の開発は以下のように進めました。
$queryRaw
に生SQLを記載してデータを取得するPick
やOmit
等のジェネリクスを活用しながら組み合わせて指定する疑似コードで示すとこのような実装の形です。
import { type example_table, prisma } from '@prisma/client';
type ExampleTableQueryResult = Array<
Pick<
example_table,
'id'
>
>;
const queryResult = await prisma.$queryRaw<ExampleTableQueryResult>`
SELECT
id
FROM
example_table;
`;
$queryRaw
を使うことで、Prismaの強みであるクエリ最適化の恩恵は得られませんでしたが、生SQLでデータ取得することで、最適化されたクエリで実行することができました。
振り返ってみるとこの$queryRaw
の活用はかなり良かったです。というのも、クエリには、ストアドファンクションを使用しなければいけなかったり、複雑なテーブルに対してサブクエリを駆使しながらクエリを書く必要がありました。
つまり、生成するSQLがかなり複雑だったのに対し、$queryRaw
のインターフェースは追加の学習コストや躓きポイントを作らず、ほぼ生SQLを実行するのと同等の手軽さで実装を進めることができました。
NestJSの公式ドキュメントで紹介されているTypeORM等、他のORMを使っていたら、このようには進まなかったと思いますし、既存DBに合わせてスキーマをアプリケーションで定義するだけでもかなりの実装工数がかかったと思います。
また、「1テーブルだけからwhereで条件指定してデータを取得する」と言ったような単純なクエリだったり、更新系のクエリに対しては、Prismaの他のAPIを使いながらかなり簡単に実装し、複雑な要件のデータ取得だけ生SQLを活用することができました。
今回は、既存のデータベースを活用しながら、NestJSとPrismaを使ってAPIサーバーを開発する際に、生SQLを活用したデータ取得の方法を紹介しました。
今現在、この開発をもう一度やり直すとしたら、SQLBuilerとしてPrismaの代わりに Kyselyを検討すると思います。Kyselyは、生SQLのようなメソッドを使いながらその結果の型を生成できるそうです。
とはいえ、$queryRaw
に対して型を当てても単体テストやバリデーションなどの実装などの他の形でクエリの結果の形を保証したり、書き捨てのクエリは一度実行して確認すれば良いだけなので、今回のような開発には十分でした。
次の記事である【運用中のDBとうまく付き合うBFF開発】② passport-localを使った認証とハッシュソルトの実装もぜひお読みください。
可茂IT塾ではFlutterインターンを募集しています!可茂IT塾のエンジニアの判断で、一定以上のスキルをを習得した方には有給でのインターンも受け入れています。
Read More可茂IT塾ではFlutterインターンを募集しています!可茂IT塾のエンジニアの判断で、一定以上のスキルをを習得した方には有給でのインターンも受け入れています。
Read More