Logicky Blog

Logickyの開発ブログです

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

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 によって利用することが出来るようになります。

<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というクエリを書きます。

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を作成します。

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 リクエストができます。

"scripts": {
  "codegen-watch": "graphql-codegen --watch"
},

GraphQL にリクエストする

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

<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}

表示内容

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