⚛️

Nuxt で GraphQL のクエリを送信する方法

2024/03/30に公開

こんにちは。 SAW です。
最近、自分の声の通りにくさに少し悩んでいます。
時々、店員さんに聞き取られないことがあるので、改善したいなと思っています。

フロントエンドを Nuxt で開発する際に、 REST API で通信する場合は、 $fetch()useFetch() などを利用します。
しかし、 GraphQL のクエリを送信する場合は、 GraphQL のクライアントライブラリを利用する方が便利です。

本記事では、 Nuxt で GraphQL のクエリを送信する方法を紹介します。
また、本記事では Nuxt 3 系の環境を想定しています。

この記事は 2024/2/29 に開催された Reboot v-kansai Meetup #15 で発表した内容を記事に書き起こしたものです。
資料を以下に貼ってありますので、ご興味のある方はご一読いただけると幸いです。

https://speakerdeck.com/azuki/nuxt-de-graphql-nokueriwosong-xin-surufang-fa

対象読者

本記事で想定する読者層は次の通りです。

  • Nuxt について基本的な知識を有している
  • GraphQL について基本的な知識を有している

Nuxt から GraphQL のクエリを送信する方法

Nuxt から GraphQL のクエリを送信する方法として、以下の手段が考えられます。

  • GraphQL のクライアントライブラリを利用する
  • HTTP 通信ライブラリでクエリを request body につけて送信する

基本的には GraphQL のクライアントライブラリを利用した方が、開発がスムーズに進みます。
そこで、 Nuxt 向けの GraphQL のクライアントライブラリを探します。

Nuxt 用の GraphQL クライアントライブラリは、 Nuxt の公式ページの Nuxt Modules から検索すると便利です。

Nuxt 用の GraphQL クライアント

Nuxt Modules で検索すると、以下のライブラリが見つかりました。

  • Nuxt GraphQL Client
    • Nuxt 用の graphql-request + GraphQL Code Generator の最小構成
  • Nuxt Apollo
    • Nuxt 用の Apollo Client
  • graphql-request
    • GraphQL クライアントとしての最小限の機能をサポートするモジュール

上記のライブラリのうち、 Nuxt GraphQL Client について以降の章で紹介します。

Nuxt GraphQL Client の特徴

Nuxt GraphQL Client の大きな特徴は以下の 3 つが挙げられます。

  • GraphQL のクエリを別ファイルに記述
  • ほぼ設定なしで利用可能
  • TypeScript 完全サポート

特に一番最初の GraphQL のクエリを別ファイルに記述できる 点が個人的推しポイントです。

GraphQL のクエリを別ファイルに記述

Nuxt GraphQL Client の大きな特徴として、 GraphQL のクエリを別ファイルに記述できます。
クエリは .gql または .graphql の拡張子のファイルに記述します。

記載した GraphQL を Vue から利用するには、 useAsyncGql() を呼び出します。
送信対象のクエリを指定するには、引数のオプションの operation から指定します。

useAsyncGql() は Nuxt の useAsyncData() と同様の構造をしたオブジェクトを返します。
data プロパティにレスポンスのデータが、 pending にはデータを取得中かの boolean が reactive な値 として格納されています。

以下に簡単なコード例を記載します。

送信する GraphQL のクエリの例
query getCountries {
  countries {
    code
    name
  }
}
useAsyncGql() でクエリのデータを取得するコード
<script setup lang="ts">
const { data, pending } = await useAsyncGql({
  operation: 'getCountries', // GraphQL のクエリ名を指定
});
</script>

<template>
  <p v-if="pending">Loading...</p>
  <div v-else>
    <ul>
      <li
        v-for="country in data.countries"
        :key="country.code"
        >
          {{ country.name }}
        </li>
    </ul>
  </div>
</template>

上記のコード例では、 GraphQL のクエリ getCountriesuseAsyncGql()operation として指定しています。
getCountries のクエリを送信すると、以下のようなデータを取得できます。

getCountries のクエリで返されるデータ
{
  "data": {
    "countries": [
      {
        "code": "ja",
        "name": "Japan"
      }
    ]
  }
}

useAsyncGql() の返り値の pending を利用して読み込み中なら Loading... と表示し、データの取得が完了したら取得したデータを data.countries から取り出して表示しています。

ほぼ設定なしで利用可能

Nuxt GraphQL Client は以下の 2 点を設定すれば、必要最小限の利用が可能です。

  1. nuxt.config.tsmodules プロパティに追加
  2. データ取得先の GraphQL サーバーの URL を .env へ追加

nuxt.config.ts の設定の追加

nuxt.config.tsmodules プロパティに 'nuxt-graphql-client' を追加します。

nuxt.config.ts
export default defineNuxtConfig({
  modules: ['nuxt-graphql-client'],
});

.env へ環境変数の追加

.envGQL_HOST という環境変数を追加し、データ取得先の GraphQL サーバーの URL を設定します。

.env
GQL_HOST="https://localhost/graphql"

TypeScript 完全サポート

GraphQL のクエリ情報をもとに、 返却型の型情報 が自動生成されます。
VSCode などのエディタで useAsyncGql() が返却するオブジェクトの data プロパティを確認すると、下図のように type hinting が表示されます。

VSCode 上での type hinting の表示
GraphQL のクエリに基づいて useAsyncGql() の返却値に型情報が VSCode 上に表示される例

型情報が生成されると、返却型だけでなく、 useAsyncGql() のオプションの operation に指定するクエリ名も 補完 で候補が表示されるようになります。

注意点として、型情報を取得するには npm dev などのコマンドを実行 する必要があります。
これは Nuxt GraphQL Client が GraphQL サーバーからスキーマ情報を取得し、さらに記述されたクエリに基づいて型情報を生成していると考えられます。
(内部の詳細な動作までは確認できていないので、あくまで推測です。)

useAsyncGql() の引数オプション

useAsyncGql() の引数にはクエリを指定する operation オプション以外にもいくつかオプションが存在します。
主要なオプションとして、以下の 2 つを紹介します。

  • variables: クエリ変数を指定
  • options.transform: クエリから取得したデータを変形する関数を指定

variables

variables には、クエリ変数を指定します。
operation と同様に、 type hinting や補完が表示されます。

VSCode 上での variables オプションの type hinting の表示
variables の型情報が VSCode 上に補完で表示される例

options.transform

useAsyncData()transform オプションと同様に、レスポンスのデータを変形する関数を指定できます。
特に TypeScript を利用している場合は、フロントエンド側の型に合うようにデータ型を変形させる際に便利です。

transform オプションで型変換をするコード例
interface Country {
  id: string;
  name: string;
}

// data は Ref<Country[]> 型になる
const { data } = await useAsyncGql({
  operation: 'getCountries',
  options: {
    transform(response): Country[] {
      // getCountries のレスポンスを Country[] に変換
      return response.countries.map((x) => ({
        id: x.code,
        name: x.name,
      }));
    },
  },
});

困っている点

これまで Nuxt GraphQL Client の基本的な使い方を説明しました。
GraphQL のクエリを Vue のコードから分割できたり、 TypeScript に対応していたりといったメリットがあることを紹介しました。

一方で、下記のような困っている点も存在します。

  • 公式ドキュメントがやや読みづらい
  • ファイルのアップロードに非対応っぽい

特に、ファイルのアップロードが非対応っぽいのは、代替手段を考えないといけないので、個人的には結構悩みの種になっています。

公式ドキュメントの読みづらさ

公式ドキュメントは存在しているのですが、使い方の詳細を理解するには少し読みづらく感じました。
特に使い慣れていない最初の段階では、ライブラリの使い方を把握するのに少し苦労するかもしれません。

また、 Stack Overflow などの公式ドキュメント以外でも情報が見つかりづらいため、情報収集は少し苦労します。

ファイルのアップロードに非対応っぽい

このライブラリではファイルのアップロードには対応していないのか、ドキュメントや GitHub の Discussions を探ってみても方法が見つかりませんでした。

Nuxt GraphQL Client は graphql-request に依存していますが、どうやらファイルを扱う機能を削除したようです。

https://github.com/jasonkuhrt/graphql-request/issues/500

かわりに middleware を利用することでファイルアップロードをサポートする方法が提案されています。

https://github.com/jasonkuhrt/graphql-request/discussions/650

ただ、 Nuxt GraphQL Client で middleware を追加する方法は見つからなかったため、どちらにしてもファイルのアップロードは現在のところは非対応と思われます。

まとめ

本記事のまとめは次の通りです。

  • Nuxt で GraphQL のクエリを送信する方法を紹介
  • Nuxt GraphQL Client の基本的な使い方を紹介

他の GraphQL クライアントのライブラリも触ってみて、良し悪しを比較してみたいなと思いました。

参考文献

https://gihyo.jp/book/2023/978-4-297-13685-7
https://nuxt-graphql-client.web.app/getting-started/quick-start

Vue・Nuxt 情報が集まる広場 / Plaza for Vue・Nuxt.

Discussion