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
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
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.ts
にGetAllFilms
というクエリを書きます。
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
を作成します。
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
下記を追加することで、npm run codegen-watch
を実行したら、コードの変更がある度に graphql-codegen が実行されて、codegen.yml の設定内容に従って、generates
で指定した場所に、gql.ts
やgraphql.ts
等が生成されます。これにより、上記で作成した GetAllFilms.ts
のコードがエラーがなくなります。あとは、この GetAllFilms
を urql
の Client にセットして実行すれば、GraphQL リクエストができます。
"scripts": {
"codegen-watch": "graphql-codegen --watch"
},
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}
こんな感じで表示されます。