0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SvelteKitでtRPCを使う

Posted at

はじめに

TypeScript界隈でtRPCが採用されるケースが増えている感覚がありますが、今回はSvelteKitでtRPCを使う方法について解説しようと思います。SvelteKitとtRPCを組み合わせることで、フルスタックのTypeScriptアプリケーションを簡単に作成できます。tRPCは、クライアントとサーバー間の通信を型安全に行うことができる素晴らしいツールです。そして、trpc-sveltekitを使うことで、SvelteKitとtRPCの統合がとても簡単になります。

tRPCとは

tRPCは、TypeScriptベースのRPC(Remote Procedure Call)フレームワークです。tRPCを使うと、APIの定義とクライアントとの通信を型安全に行うことができます。これにより、エンドポイントごとに異なる型を定義しなくても、TypeScriptの型推論を最大限に活用できるようになります。tRPCの主な特徴は以下の通りです。

  • 型安全: サーバーとクライアント間の通信が完全に型安全。
  • シンプル: 簡単にセットアップして使用できる。
  • 柔軟: RESTやGraphQLのような特定のプロトコルに縛られない。

trpc-sveltekitとは

trpc-sveltekitは、SvelteKitプロジェクトでtRPCを簡単に統合できるパッケージです。このパッケージを使うことで、SvelteKitの強力な機能とtRPCの型安全な通信を組み合わせることができます。trpc-sveltekitは、SvelteKitのエンドポイントとtRPCのルーターをシームレスに統合し、開発者の負担を軽減します。

導入方法

SvelteKitのプロジェクトがすでにセットアップ済みである前提で、必要なパッケージのインストールをしてゆきます。

npm install @trpc/server @trpc/client trpc-sveltekit

tRPCルーターの設定

src/lib/trpc/router.tsを作成し、以下のコードを追加します。

import type { Context } from '$lib/trpc/context';
import { initTRPC } from '@trpc/server';
import delay from 'delay';

export const t = initTRPC.context<Context>().create();

export const router = t.router({
  greeting: t.procedure.query(async () => {
    await delay(500); // 👈 500msかかる処理をシミュレーション
    return `Hello tRPC @ ${new Date().toLocaleTimeString()}`;
  })
});

export type Router = typeof router;

tRPC Contextを作成

src/lib/trpc/context.tsを作成し、以下のコードを追加します。

import type { RequestEvent } from '@sveltejs/kit';
import type { inferAsyncReturnType } from '@trpc/server';

export async function createContext(event: RequestEvent) {
  return {
    // eventからlocalsやurlなどのオブジェクトが取得できます
  };
}

export type Context = inferAsyncReturnType<typeof createContext>;

handleにtRPCHandleを追加

src/hooks.server.tsのhandleに以下のコードを追加します。

import { createContext } from '$lib/trpc/context';
import { router } from '$lib/trpc/router';
import type { Handle } from '@sveltejs/kit';
import { createTRPCHandle } from 'trpc-sveltekit';

// sequenceを使って複数のhandleを追加する例
export const handle: Handle = sequence(
  somthingHanfle,
  createTRPCHandle({ router, createContext })
);

ヘルパー関数の作成

PageでtRPCを簡単に使用できるように、lib/trpc/client.tsにヘルパー関数を作成します。

import type { Router } from '$lib/trpc/router';
import { createTRPCClient, type TRPCClientInit } from 'trpc-sveltekit';

let browserClient: ReturnType<typeof createTRPCClient<Router>>;

export function trpc(init?: TRPCClientInit) {
  const isBrowser = typeof window !== 'undefined';
  if (isBrowser && browserClient) return browserClient;
  const client = createTRPCClient<Router>({ init });
  if (isBrowser) browserClient = client;
  return client;
}

関数を実行してみる

src/routes/+page.svelteに、以下のようなpageを作成します。

<script lang="ts">
  import { page } from '$app/stores';
  import { trpc } from '$lib/trpc/client';

  let greeting = 'ボタンをクリックしてデータを取得';
  let loading = false;

  const loadData = async () => {
    loading = true;
    // tRPC Routerに作成した関数を実行する
    greeting = await trpc($page).greeting.query();
    loading = false;
  };
</script>

<h6>Loading data in<br /><code>+page.svelte</code></h6>

<a
  href="#load"
  role="button"
  class="secondary"
  aria-busy={loading}
  on:click|preventDefault={loadData}>Load</a
>
<p>{greeting}</p>

ボタンをクリックすると500msのディレイの後に「Hello tRPC」というメッセージが表示されます。

引数を渡してみる

Zodを使用して引数のスキーマを定義することができます。
Router内の処理が実行される前に引数のバリデーションチェックも実施されます。
例として src/lib/trpc/router.ts を以下のように改変します。

// Zodスキーマ
const schema = z.object({
  message: .string().min(1)
});

export const router = t.router({
  // input関数を使ってスキーマを設定します
  greeting: t.procedure.input(schema).query(async ({ input }) => {
    ...
    // inputオブジェクトからスキーマの値を取得できます
    return `Hello tRPC @ ${input.message}}`;
  })
});

引数を指定して関数を実行

src/routes/+page.svelteも併せて改変します。

<script lang="ts">
  ...

  const loadData = async () => {
    ...
    // tRPC Routerに作成した関数を実行する
    greeting = await trpc($page).greeting.query({ message: 'Japan' });
    ...
  };
</script>
...

ボタンをクリックすると「Hello tRPC @ Japan」というメッセージが表示されるようになりました。

情報の更新を伴う関数

query()はGETメソッドでリクエストされますが、POSTメソッドはmutation()という関数を使用します。
mutationは、データの作成、更新、削除などを行うために使用されます。
mutationを使用するためにsrc/lib/trpc/router.tsにmutation用のルーティングを追加してゆきます。

// Zodスキーマ
const schema = z.object({
  message: .string().min(1)
});

export const router = t.router({
  greeting: ...,
  postMessage: t.procedure.input(schema).mutation(async ({ ctx, input }) => {
    // 更新を伴う処理など

    // オブジェクトを返却することもできます
    return {
        id: ...
    }
  }
});

Pageから実行する

実行の仕方はquery()と同じです。

const result = await trpc().createUser.mutate({
  message: 'Earth'
});

// 返り値も型安全です
// { id: xxxxxx }
result

まとめ

以上で、SvelteKitとtRPCを使用する方法の説明となります。tRPCは、型安全な通信を提供し、開発者の生産性を向上させる素晴らしいツールです。trpc-sveltekitを使えば、SvelteKitとの統合も簡単に行えます。ぜひ、この組み合わせを試してみてください。

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?