Skip to content

urql について

2021-06-14


自作 GraphQL client を実装しようと思い、小さめライブラリの urql を参考にしようと思ったけど基礎知識が足りてないと感じたのでメモする。
そもそもこれを知った理由として、preact のコアコミッターの Jovi 氏 が urql のコアコミッターでもあることがあり、初めて GraphQL を使ったときも preact と一緒にこれを使用した。

urql とは

GraphQL クライアント、Apollo よりも軽量でシンプルなキャッシュの仕組みが提供されてるらしい。
express の middleware に似たような Exchange による拡張性が提供されてる(ここがいまいち理解できなかった)
外部のライブラリとして、stream を扱う wonka@graphql/typed-document-node を使用してる。

使い方

client を作成して Provider で囲うだけです。
Apollo でいう ApolloClientcreateClient となっています。

import { createClient } from '@urql/core';

const client = createClient({
  url: 'http://localhost:3000/graphql',
});
1
2
3
4
5

1回のみクエリを送信したい場合は以下のようにします。
client.mudation にすることで mutation を送信することもできます。

const QUERY = `
  query Test($id: ID!) {
    getUser(id: $id) {
      id
      name
    }
  }
`;

client
  .query(QUERY, { id: 1 })
  .toPromise()
  .then(result => {
    console.log(result); // { data: ... }
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

キャッシュをクエリから同期的に読み込むには readQuery を使用します。

const QUERY = `
  query Test($id: ID!) {
    getUser(id: $id) {
      id
      name
    }
  }
`;

const result = client.readQuery(QUERY, { id: 1 });

result; // null or { data: ... }
1
2
3
4
5
6
7
8
9
10
11
12

キャッシュの仕組み

urql は documeht caching という仕組みがある。
全てのクエリと変数の組み合わせはハッシュ化され、レスポンスと共にキャッシュされる。
コードで言うと ここらへん
WeakMap を用いてキャッシュが保持され、ハッシュとして格納されている。
ハッシュには djb2 が使われている。

つまり、1度キャッシュされたクエリと同じクエリの場合はリクエストを送らずにキャッシュされているデータを返すといった風になっている。
また、__typename が同じ mutation が送られた時にはリソースの更新とみなされ、キャッシュがクリアされる。
stringifyVariables.ts で stringifyVariablesstringify がそれぞれ実装されてるのはここらへんの仕組みが主な理由。

urql のキャッシュ

urql は大きくわけて4つのキャッシュコントロールが実装されている。

ポリシー内容用途
cache-first1回目のリクエストでキャッシュをして、キャッシュがあればリクエストは投げずそのキャッシュを返す変更の少ないリソースへのアクセス
cache-onlyリクエストを投げずにキャッシュのみを返す普通は使わないわね...。
network-onlycache-only の逆。キャッシュは使わずに常にリクエストを投げる変更の多いリソースへのアクセス
cache-and-networkキャッシュがあればキャッシュを返し、その後リクエストを投げる頻繁には変更がされない、早く見せたいリソースへのアクセス

このようになっている。それぞれの使い方について理解したい。

Exchange

ここがわからなかった、実装してて謎になってしまった。(まだ実装できてないんだけど)
どうやら urql ではリクエスト関数を operation という単位で扱う(最初 operation ってなんだって思いながらコード書いてた)
このライフサイクルはリクエストを投げてから変えてくるまでの双方向の流れを stream 的に扱う、このための wonka。

urql のキャッシュは Exchange を使用して全て設定することができる。
上でも述べたが、cacheExchange は document cache を提供する。
urql の正規化されたキャッシュは @urql/exchange-graphcache として提供されている。

Exchanges には以下の特徴がある。

  • 正規化されたキャッシュ
  • カスタムのキャッシュとその解決
  • Subscription と Mutation によるキャッシュの更新
  • 最適化された Mutation の更新
  • スキーマの認識
  • オフラインサポート
  • エラーと警告

長くなりそうなので Graphcacheについて という別記事にする。