フロントエンドにおけるGraphQLクエリの流れと基本構成
GraphQLの操作を理解するためには、「クエリ」「リゾルバ」「データソース」「スキーマ」の役割を把握することが重要である。それぞれの要素がどのように連携してデータ取得までの流れを構成しているかをまとめた。フォルダ構成はこのページの下をご参照ください。
GraphQLクエリの基本形
GraphQLクエリの基本形として、以下のようなクエリを使用して特定のユーザーの情報を取得する
query GetUser($userId: ID!) {
user(id: $userId) {
name
email
}
}
1. GraphQLクエリが送信される
まず、クライアントからGraphQLサーバーにクエリが送信される。
import { gql, useQuery } from '@apollo/client';
//クエリの定義
const GET_USER = gql`
query GetUser($userId: ID!) {
user(id: $userId) {
name
email
}
}
`;
//クエリの実行
const { loading, error, data } = useQuery(GET_USER, {
variables: { userId: "123" },
});
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<div>
<p>Name: {data.user.name}</p>
<p>Email: {data.user.email}</p>
</div>
);
2. サーバーがクエリを解析する
GraphQLサーバーは、クエリを受け取ると、スキーマを基に内容を解析し、適切なリゾルバを判断する。スキーマは、すべてのクエリ、ミューテーション、サブスクリプション、および関連するデータ型を定義し、通常1つのファイルにまとめられるが、複数ファイルに分割する場合もある。
import { ApolloServer } from 'apollo-server';
import { makeExecutableSchema } from 'graphql-tools';
import { resolvers } from './resolvers/userResolver';
// スキーマの定義
const typeDefs = `
type User {
name: String
email: String
}
type Query {
user(id: ID!): User
}
`;
// スキーマとリゾルバを結びつけて、サーバーで使用できる形にする
const schema = makeExecutableSchema({
typeDefs,
resolvers,
});
// サーバーの初期化
const server = new ApolloServer({ schema });
// サーバーの起動
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
「1. GraphQLクエリが送信される」のGetUserクエリでは、userフィールドに対応するリゾルバが、このスキーマに基づいて次の段階(3. リゾルバが呼び出される)で呼び出される。
3. リゾルバが呼び出される
次に、解析されたクエリに対応するリゾルバが呼び出される。リゾルバは、指定されたクエリに基づいてデータを取得し、そのデータを返す。
const resolvers = {
Query: {
user: async (_, { id }, { dataSources }) => {
return dataSources.userAPI.getUserById(id);
},
},
};
この例では、userId
を引数として受け取り、データソースのgetUserById
メソッドを呼び出すことで、指定されたユーザーのデータを取得する。
4. データソースが呼び出される
リゾルバからデータソースが呼び出される。データソースは、実際にデータを取得するための手段を提供する。データソースは、API、データベース、その他の外部リソースと通信し、必要なデータを取得する。
class UserAPI {
async getUserById(id) {
const response = await fetch(`https://api.example.com/users/${id}`);
const data = await response.json();
return {
name: data.name,
email: data.email,
};
}
}
この例では、id
に基づいて外部APIからユーザー情報を取得し、それをリゾルバに渡す。
5. データがリゾルバを通じて返され、最終的にクライアントに返される
データソースから取得されたデータは、リゾルバを通じてクライアントに返される。この一連の流れが、GraphQLを使ったデータ取得の基本プロセスである。
//クライアント側では、取得したデータを次のように使用する
return (
<div>
<p>Name: {data.user.name}</p>
<p>Email: {data.user.email}</p>
</div>
);
GraphQLのデータソース
データソースとは、一般的に、データが保管されている場所やそのデータにアクセスするための手段のことであり、データベース、API、ファイルシステムなどが該当する。GraphQLにおいては、外部のデータソースからデータを取得するためのロジックを含んだメソッドやクラスがデータソースと呼ばれることが多い。
GraphQLのフロントエンド操作の構成要素
GraphQLのフロントエンド操作は、「クエリ」「リゾルバ」「データソース」から成り立っている。リゾルバ内にデータソースが含まれることもある。
プロジェクトのフォルダ構成
このページの説明に基づくフォルダ構成は以下の通りである。これは、GraphQLを多く使わない場合の例であり、小規模なプロジェクトや特定の機能にGraphQLを利用する場合に適している。
src/
│
├── graphql/
│ ├── resolvers/
│ │ └── userResolver.ts
│ ├── datasources/
│ │ └── UserAPI.ts
│ └── schema.ts
│
├── components/
│ └── UserDisplay.tsx
│
└── index.tsx
また、「1. GraphQLクエリ」で説明したクエリ部分を切り離す構成も推奨される。
src/
│
├── graphql/
│ ├── queries/
│ │ └── GetUserQuery.ts
│ ├── resolvers/
│ │ └── userResolver.ts
│ ├── datasources/
│ │ └── UserAPI.ts
│ └── schema.ts
│
├── components/
│ └── UserDisplay.tsx
│
└── index.tsx
Discussion