GraphQL クライアントを使っていると、データ取得後にデータ変換がしたくなりませんか。私はしたくなります。 GraphQL クライアントの urql で、データ変換するのに、exchanges が使えそうだったので、それを共有します。
サンプルコードは、次のリポジトリに置いています。
Exchanges とは、公式ページより引用します。
The Client itself doesn't actually know what to do with operations. Instead, it sends them through "exchanges". Exchanges are akin to middleware in Redux and have access to all operations and all results. Multiple exchanges are chained to process our operations and to execute logic on them, one of them being the fetchExchange, which as the name implies sends our requests to our API.
ざっくりいうと、GraphQL の通信フロー(リクエスト/レスポンス)にアクセスできる機構です。レスポンスにアクセスできるため、 データ変換もできます。exchanges にデータ変換を一手に引き受けるため、useQuery などクエリ発行する側で、何度も変換コードを書く必要がなくなります。
サンプルコードを紹介する前に、GraphQL のデータソースとして Pokemon を使います。 URL とクエリは、次のものを使います。
https://trygql.formidable.dev/graphql/basic-pokedexquery Pokemons {
pokemons {
id
name
}
}データ変換は、次のようなコードを書きます。
map の部分が、実際のデータ変換になります。今回は、name をtoLowerCaseしています。
export const transformExchange = ({ forward }) => {
return (ops$) =>
pipe(
ops$,
forward,
// Sample transform code
map((result) => {
const { data } = result;
if (!data || !data.pokemons) {
return result;
}
const { pokemons } = data;
result.data.pokemons = pokemons.map((pokemon) => {
pokemon["name"] = pokemon.name.toLowerCase();
return pokemon;
});
return result;
})
);
};transformExchange 関数を urql のクライアントに渡します。
import { createClient, fetchExchange } from "urql";
import { transformExchange } from "./transformExchange";
client = createClient({
url: "https://trygql.formidable.dev/graphql/basic-pokedex",
exchanges: [transformExchange, fetchExchange],
});exchanges は、何も指定しない場合、defaultExchangesが使われます。今回、必要最低限の説明のために、defaultExchangesの内の fetchExchange だけ使いました。
あとは、次のコードのように useQuery でデータ取得すれば良いです。データ取得後のデータは、データ変換された結果になっています。
import { useQuery } from "urql";
const PokemonsQuery = `
query Pokemons {
pokemons {
id
name
}
}
`;
export const Pokemons = () => {
const [result] = useQuery({
query: PokemonsQuery,
});
const { data, fetching, error } = result;
if (fetching) return <p>Loading...</p>;
if (error) return <p>Oh no... {error.message}</p>;
return (
<ul>
{data.pokemons.map((pokemon) => (
<li key={pokemon.id}>{pokemon.name}</li>
))}
</ul>
);
};pokemon.name が toLowerCase されています。
urql の exchanges って、wonkaというReason言語で書かれたライブラリに依存しているので、調査するのが少し苦労しました。
-
タグ「バックエンド」の記事
はじめに tRPCは、型安全なAPIを簡単に構築できるフレームワークです。開発中、バックエンドの実装を待たずに、Storybook上でフロントエンドの開発を進めたい場合、Mock Service Worker (MSW) を使用してAPIのモックを行うことができます。この記事では、maloguertin/msw-trpc を用いて、tRPC通信をMSWでモックする方法について解説します。実用例として、サンプルコードをGitHubリポジトリ silverbirder/trpc-msw-storybook-nextjs で共有しています。
Stable Diffusion は、文章を渡すと画像を生成してくれる AI で OSS です。これを自前で動かそうとすると、GPU が必要になります。
タグ「フロントエンド」の記事
最近、ヒューマンインターフェース ガイドライン(HIG)という言葉を知りました。 「ヒューマンインターフェイスガイドライン」には、どのAppleプラットフォームでも優れた体験を設計できるようにするためのガイドとベストプラクティスが含まれてい
2026-01-24
主にWeb関連の個人開発をしている際に心がけていることを書きます。 月末に近づくにつれ、AIの利用上限に達してしまうことがあります。 その状況になった時、以下のいずれかの選択肢が私の中では残っています。 課金して利用上限を増やす 無料モデル
個人サイトをリニューアルをしています。 ノート風のデザインを目指して、スタイルを調整していました。 ノートの見た目は、現実にあるノートを再現しようとCSSを書いていました。 現在、以下の画像のようなノートになっています。 ノート風デザインの
2026-01-20
タグ「JavaScript」の記事
zodのrefineを使っていたのですが、pathの使い方を全く理解できておらず、小一時間ほどハマってしまったことがあったので、備忘録として残しておきます。