はじめに
SvelteKitは公式ドキュメントが(体感)読みやすいですね!
しかし、公式ドキュメントではDBを利用するにはどうすればいいのかが、
ふんわりとしか書かれていないため、実際に理解のためにSvelteKitからDB接続を試してみたいと思います。
個人的に理解した内容になるため、誤りやもっと良い方法などがあればコメント頂けると嬉しいです。
前提
- 開発環境:Windwos10
- 主なバージョン
- SvelteKit:1.0.0
- Node.js:v16.16.0
- Postgresql:PostgreSQL 12.2, compiled by Visual C++ build 1914, 64-bit
Postgresqlの準備
今回はDBに特にこだわりがなかったため、PostgreSQLを使用しました。
ローカル開発環境用にインストールする場合、次の記事が参考になると思われます。
SvelteKitの準備
公式ドキュメントに従って、SvelteKitのプロジェクトを作成します。
フロント画面の作成
今回は簡単なデータの登録・取得を試したいため、ふりかえりを記録できるアプリを作りたいと思います。
画面には、入力欄と入力結果一覧を表示させます。
画面の動きとしては、入力欄に入力した内容をDBに登録し、入力結果一覧をDBから取得していきます。
データの取得
なにかしらのデータをDBから取得して、画面上で使用したい場合は、まず「+page.svelte」にdata変数を定義します。
<script lang='ts'>
import LookBackList from '$lib/component/LookBackList.svelte'
import type { PageData } from './$types';
export let data: PageData;
</script>
そして、DBから値を取得するには、load関数をexportする「+page.server.ts」ファイルを作成します。
このload関数の返り値が、「+page.svelte」のdata変数に格納されます。
import type { PageServerLoad } from './$types';
import { getAllFromKptTable } from '$lib/server/db';
export const load = ( async () => {
// DBから値を取得
const allLookBack = await getAllFromKptTable();
// 取得結果を整形して返却
const keeps = allLookBack.filter((lookBack: any) => lookBack.type === 'Keep');
const problems = allLookBack.filter((lookBack: any) => lookBack.type === 'Problem');
const trys = allLookBack.filter((lookBack: any) => lookBack.type === 'Try');
return {
LookBacks: {
keepLookBacks: keeps,
problemLookBacks: problems,
tryLookBacks: trys,
},
}
}) satisfies PageServerLoad;
DBからの値の取得には「node-postgres」というライブラリを使用します。
「src/lib/server/db.ts」ファイルを作成し、次のように修正します。
import pg from 'pg';
export const initDataBaseConnect = () => {
return new pg.Client({
database: "hoge", // データベース名
user: "hoge", // ユーザー名
password: "hoge", // パスワード
host: "127.0.0.1",
port: 5432,
});
}
export const getAllFromKptTable = async () => {
const pgClient = initDataBaseConnect();
await pgClient.connect();
const result = await pgClient.query(`SELECT * FROM kpt`);
await pgClient.end()
return result.rows;
}
「node-postgres」の使用方法については、以下のサイトを参考にしました。
ここまでの修正でDBから値を取得することができます。動作を確認してみましょう。
pgAdminを使用して、データを登録します。
INSERT INTO kpt VALUES ('Keep', 'Keepテスト', '001'), ('Problem', 'Problemテスト', '002'), ('Try', 'Tryテスト', '003');
画面にてデータが正しく取得できるか確認してみます。完璧ですね!
データの登録
次に画面上でユーザが入力した値を使って、DBにデータの登録を試してみます。
画面上の「add」ボタンを押下するとリクエストが飛ぶように修正します。
<script lang='ts'>
// import分や変数定義、その他処理は省略...
const sendInputText = () => {
if (inputText.length > 0) {
const param = {
'lookBack': inputText,
'lookBackType': lookBackType,
};
fetch(addLookBackUrl, {
method: 'POST',
body: JSON.stringify(param),
}).then((res) => {
inputText = '';
dispatch('clickAddButton');
})
}
}
</script>
<div>
<input type='text' name='lookBack' bind:value={inputText} />
<button on:click={sendInputText}>add</button>
</div>
リクエストに対応するサーバの処理を「src/routes/api/lookback/add/+server.ts」に記述していきます。
上記ファイルには、データの取得と同じ流れでDBに接続しますが、
DB接続用のClientのインスタンス生成については「src/hooks.server.ts」に記載し、インスタンスをevent.localsに格納します。
(必ずしもhooksでインスタンス生成する必要があるかは自信ないです。。。)
import type { Handle } from '@sveltejs/kit';
import { initDataBaseConnect } from '$lib/server/db'
export const handle = (async ({event, resolve}) => {
event.locals.db = initDataBaseConnect();
const response = await resolve(event);
return response;
}) satisfies Handle;
import { json } from "@sveltejs/kit";
import type { RequestHandler } from "./$types";
import uuid from 'uuid';
export const POST = (async ({locals, request}) => {
const data = await request.json();
const newId = uuid.v4();
await locals.db.connect();
await locals.db.query(`INSERT INTO kpt(id, type, lookback) VALUES('${newId}', '${data.lookBackType}', '${data.lookBack}')`);
await locals.db.end();
return json({});
}) satisfies RequestHandler;
hooks.server.tsとは、リクエストの処理である「+server.ts」の処理の前に行うインターセプターみたいなものと理解しています。
詳しくは、公式ドキュメントを参照してください。
これでDBへのデータ追加の処理が完成したため、動作を確認してみます。上手くいきました!
最終的なフォルダ構成
今回作成したプロジェクトのsrc配下のフォルダ構成は次の通りになりました。
src
├─lib
│ ├─component // コンポーネントの配置ディレクトリ
│ │ ├─ LookBackList.svelte
│ │ └─ SendText.svelte
│ ├─images
│ ├─server
│ │ └─ db.ts // DBの初期化処理を定義
│ └─typescript
├─routes
│ ├─api
│ │ └─lookback
│ │ ├─add
│ │ │ └─ +server.ts // レコード登録のAPI処理
│ │ └─getByType
│ │ └─ +server.ts // Type別レコード取得のAPI処理
│ ├─ +page.server.ts // レンダリング前のデータ取得処理定義
│ ├─ +page.svelte // 画面定義
│ └─ style.css
└─ hooks.server.ts // hook処理の定義
まとめ
躓く箇所もあったりしましたが、無事にSvelteKitからDB接続をすることができて良かったです。
ドキュメントを読むだけでなく、手を動かすのがやはり勉強になりますね。
参考文献
- SvelteKitドキュメント:https://kit.svelte.jp/docs/introduction(2023-01-18参照)