SvelteKitでurqlとgraphql-codegen(client-preset)を使って GraphQLサーバにリクエストする

2023/05/03

SvelteKit で urql と graphql-codegen を使って GraphQL サーバにリクエストするメモです。graphql-codegen の client-preset というのを使っています。 リクエストする GraphQL サーバは下記を使わせていただきました。
https://swapi-graphql.netlify.app/

実際に作成したリポジトリは下記です。

https://github.com/edo1z/svelte-urql-codegen-sample

目次

SvelteKit プロジェクトの作成

npm create svelte@latest svelte-urql-codegen-sample
cd svelte-urql-codegen-sample
npm i

各種インストール

npm i -D @graphql-codegen/cli @graphql-codegen/client-preset @urql/svelte

urql の client を使えるようにする

src/routes/+layout.svelte に下記を書きます。ルートの layout で setContextClient を実行することで、それ以外の子のコンポーネントで urql の client を getContextClient によって利用することが出来るようになります。

src/routes/+layout.svelte
<script>
  import {
    createClient,
    setContextClient,
    cacheExchange,
    fetchExchange,
  } from "@urql/svelte";
  const client = createClient({
    url: "https://swapi-graphql.netlify.app/.netlify/functions/index",
    exchanges: [cacheExchange, fetchExchange],
  });
  setContextClient(client);
</script>

<slot />

クエリの作成

下記ディレクトリを作成します。(このディレクトリは codegen.yml の設定次第で任意の場所・名前に変更可能です)

mkdir -p src/lib/queries

src/lib/queries/film/GetAllFilms.tsを作成します。これは、src/lib/queries に GraphQL リクエストで使うクエリをまとめて配置する想定です。GetAllFilm.tsGetAllFilmsというクエリを書きます。

src/lib/queries/film/GetAllFilms.ts
import { graphql } from '$lib/gql/gql';

export const GetAllFilms = graphql(/* GraphQL */ `
	query GetAllFilms {
		allFilms {
			totalCount
			films {
				title
				episodeID
				releaseDate
			}
		}
	}
`);

上記コードで、src/lib/gql/gqlをインポートしようとしていますが、今はありません。src/lib/gql内のファイルは、graphql-codegen によって自動作成されます。ですので、上記コードは現時点ではエラーになります。

codegen.yml の作成

プロジェクトルートに下記のcodegen.ymlを作成します。

codegen.yml
ignoreNoDocuments: true
schema: https://swapi-graphql.netlify.app/.netlify/functions/index
documents:
  - "src/lib/queries/**/*.ts"
generates:
  src/lib/gql/:
    preset: client-preset
    config:
      useTypeImports: true

package.json の設定と graphql-codegen の実行

下記を追加することで、npm run codegen-watchを実行したら、コードの変更がある度に graphql-codegen が実行されて、codegen.yml の設定内容に従って、generatesで指定した場所に、gql.tsgraphql.ts等が生成されます。これにより、上記で作成した GetAllFilms.ts のコードがエラーがなくなります。あとは、この GetAllFilmsurql の Client にセットして実行すれば、GraphQL リクエストができます。

package.json
"scripts": {
  "codegen-watch": "graphql-codegen --watch"
},

GraphQL にリクエストする

src/routes/+page.svelteで、GraphQL リクエスト(GetAllFilms)をして、レスポンス内容を表示させてみます。

src/routes/+page.svelte
<script>
  import { getContextClient, queryStore } from "@urql/svelte";
  import { GetAllFilms } from "$lib/queries/film/GetAllFilms";

  const filmsStore = queryStore({
    client: getContextClient(),
    query: GetAllFilms,
  });
</script>

<h1>Films</h1>
{#if $filmsStore.fetching}
  <p>LOADING...</p>
{:else if $filmsStore.error}
  <p>ERROR! {$filmsStore.error.message}</p>
{:else if $filmsStore.data?.allFilms?.films}
  <ul>
    {#each $filmsStore.data.allFilms.films as film}
      {#if film}
        <li>
          {film.title} - Episode {film.episodeID} - Released on {film.releaseDate}
        </li>
      {/if}
    {/each}
  </ul>
{:else}
  <p>NO films found.</p>
{/if}

表示内容

こんな感じで表示されます。

films

Rust🦀, Network⚡, PostgreSQL🐘, Unity🎮

Tags

rust  (9)
rocket  (7)
svelte  (5)
c++  (4)
vscode  (3)
sqlx  (3)
glfw  (2)
opengl  (2)
nestjs  (2)
render  (2)
wsl2  (2)
goerli  (1)
geth  (1)
nft  (1)
gui  (1)
tetris  (1)
jwt  (1)
prisma  (1)
urql  (1)
mdsvex  (1)
tmux  (1)
nvim  (1)
axum  (1)
vim  (1)
pacman  (1)
Cursor  (1)
VSCode  (1)
PHP  (1)