SvelteKit で JSON ベースの API を TypeScript で実装
SvelteKit で JSON ベースの API を TypeScript で実装する方法を紹介します。クライアントサイド、サーバーサイド両方の実装例を紹介していますが、特にサーバーサイドの TypeScript の型を中心に紹介します。
やりたいこと
SvelteKit で JSON ベースの API を作ろうとしています。JavaScript での実装は SvelteKit のチュートリアル API routes / GET handlers • Svelte Tutorial を見れば分かりますが、TypeScript での書き方がわからなかったので調べました。
環境
- OS
- Microsoft Windows 21H2
- Node.js
- 18.16.0
- svelte
- 4.0.5
- @sveltejs/kit
- 1.20.4
SvelteKit での JSON ベースの API の実装
クライアントサイド
以下のページを /src/route/todo/+page.svelte
として作成します。ボタンを押すと POST リクエストが飛ぶ簡単なページです。
サーバーサイド
以下のサーバー側のエンドポイントを /src/route/api/todo/+server.ts
として作成します。POST されてきた body
をそのまま返すやまびこエンドポイントです。/src/route
以下のパスがクライアントサイドでリクエストする URL パスと一致していることに注意してください。
チュートリアルにも以下記載がありますが、対応する HTTP メソッドである POST
関数を作成しエクスポートしています
+server.js
ファイルを追加し、そこで HTTP メソッドGET
、PUT
、POST
、PATCH
、DELETE
に対応する関数をエクスポートすることで、 API ルート(API routes) を作成することもできます。
さてこの HTTP メソッドに対応する関数ですが、RequestHandler
(Types • Docs • SvelteKit) という型が用意されています。
RequestHandler
は RequestEvent
(Types • Docs • SvelteKit) を引数で受け取り、Web API 標準の Response
(Response - Web API | MDN) を返す型となっています。
RequestEvent
は Web API 標準の Request
(Request - Web API | MDN) や URL
(URL - Web API | MDN) 等が含まれており、ここでは request
のみ使うので分割代入で取得しています。
なお、RequestHandler
は本来パスパラメータとパスの型を示す 2 つのジェネリクスを持っているのですが、ここでは指定しておりません。この理由は次項の Generated Type で説明します。
ちなみに SvelteKit の json()
(Modules • Docs • SvelteKit) を使用することで、JSON 文字列に変換された Response
オブジェクトが得られるので、以下のような書き方でもよいです。
Generated Type
/src/route/api/todo/+server.ts
の 1 行目に注目してください。./$types
からインポートしていますが、/src/routes/api/todo
ディレクトリに ./$types.d.ts
ファイルはありません。では一体何をインポートしているのでしょう。
SvelteKit はコンパイル後の JavaScript を /.svelte-kit/generated
ディレクトリに生成しますが、そのほかに TypeScript の型も /.svelte-kit/types
に生成します。
/.svelte-kit/types/src/routes
以下には /src/routes
以下と同じディレクトリ構成が生成されています。
/.svelte-kit/types/src/route/api/todo
を見てみましょう。$types.d.ts
が生成されています。
ここで RequestHandler
型がエクスポートされています。RequestHandler
は元々パスパラメータとパスを示す 2 つのジェネリクスを持っているのですが、ここでそれぞれの型を渡した上でエクスポートされているため、RequestHandler
を作成するたびにパスパラメータやパスの型を定義する必要がなくなります。
さて次に何故 /.svelte-kit/types/src/route/api/todo/$types.d.ts
が /src/route/api/todo/+server.ts
から同じディレクトリにあるように見えるかについてですが、TypeScript の rootDirs
で実現しています。
Using rootDirs, you can inform the compiler that there are many “virtual” directories acting as a single root. This allows the compiler to resolve relative module imports within these “virtual” directories, as if they were merged in to one directory. ー TypeScript: TSConfig Reference - Docs on every TSConfig option
/.svelte-kit/tsconfig.json
を見てみると以下設定があります。
これにより、/.svelte-kit/tsconfig.json
から見た ..
であるプロジェクトルート /
以下と ./svelte-kit/types/
以下はマージされたようになり、/.svelte-kit/types/src/route/api/todo/
と /src/route/api/todo/
は同じディレクトリであるかのように扱うことができます。
あとがき
SvelteKit は最近人気なようですが日本語の情報がまだまだ少なく調べるのは結構大変ですが、公式の情報が充実しているのでしっかり探せば十分開発できそうだなと思いました。しばらく SvelteKit で遊んでみようと思います。