実現したいこと
GraphQLのスキーマでバックエンドgqlgen
を使用していて、レスポンスの項目としてTimeの
scalarを使用します。その際にフロントエンド側ではDateとして扱いたいので、codegenのgenerates設定で以下のように設定します。
generates: {
"./src/graphql/gen/graphql.tsx": {
plugins: ["typescript", "typescript-operations", "typescript-urql"],
config: {
scalars: {
Time: "Date",
},
},
},
}
ただ、このままだとDateにparseされず文字列の状態で入ってきてしまうので、このDateのparseをどこかに実装したいというのがやりたいことです。
対応方法
まず挙げられるのはurqlでデータ変換(transform)してみたで紹介されている通り、transformExchangeを使用する方法です。ただ、自前で実装するのではなく何か良さげなライブラリあるかなと思って探してみたところ、urqlのドキュメントShowcaseを見てみたら、urql-custom-scalars-exchange
というのがあったので今回はこれを試してみました。
urql-custom-scalars-exchangeの留意点
ドキュメントからリンクを辿ると、このライブラリは直近(2025年5月時点)更新されておらずProjectstatusのissueで言及されている通り、今後メンテナンスされない見込みとのことです。
ただ、このライブラリをフォークしたatmina/urql-custom-scalars-exchangeがあり、使えそうな雰囲気だったのでとりあえず今回はこれを使用してみます。
前提
- 使用したurqlのバージョンは
4.2.2
です。 - 使用したatmina/urql-custom-scalars-exchangeのバージョンは
1.1.1
です。
実装サンプル
urqlのクライアントを作成する実装は以下の通りとなります。
import {
cacheExchange,
createClient,
fetchExchange,
} from "urql";
import customScalarsExchange from "@atmina/urql-custom-scalars-exchange";
import schema from "@/graphql/gen/introspection.json";
// urqlクライアント作成関数
const createUrqlClient = (token?: string) => {
const scalarsExchange = customScalarsExchange({
// eslint-disable-next-line @typescript-eslint/no-explicit-any
schema: schema as any, // なぜか型エラーになるのでanyにしておく・・
scalars: {
Time(value) {
return new Date(value);
},
},
});
return createClient({
url: `${process.env.NEXT_PUBLIC_API_URL}`,
exchanges: [scalarsExchange, cacheExchange, fetchExchange],
fetchOptions: () => ({
headers: {
Authorization: token ? `Bearer ${token}` : "",
},
}),
});
};