アプリケーションのデータを取得するためにREST APIよりも良い方法があるのではないかと考えたことはありますか?バックエンド開発において、GraphQLは強力な代替手段として登場し、データ取得に対してより柔軟で効率的なアプローチを提供します。Javaに精通した開発者にとって、GraphQLを現代のバックエンドに統合することは、さまざまなユースケースに合わせたスケーラブルで高パフォーマンスなAPIへの扉を開きます。
このブログでは、GraphQLとRESTの主な違いを探り、データ取得におけるGraphQLのユニークな利点を強調し、実際の例を用いてJavaでのGraphQL APIの実装について案内します。
GraphQLとは何ですか?
GraphQLはAPI用のクエリ言語であり、そのクエリを実行するためのランタイムです。固定されたエンドポイントが事前定義されたデータを返すRESTとは異なり、GraphQLはクライアントが必要なデータを正確に要求できるようにします。この詳細さにより、GraphQLは特に複雑またはデータ集約型のアプリケーションに対して非常に効率的です。
GraphQLアプローチの利点:
- 詳細なデータ取得:クライアントは、部門のような不要なフィールドを取得せずに、名前と役職のみをクエリできます。
- ネストされたクエリ:従業員情報とともにマネージャーの詳細を1つのクエリで取得できます。
- スキーマ駆動型開発:スキーマは契約として機能し、APIの進化を容易にします。
REST APIとは何ですか?
表現状態転送(REST)は、APIを構築するためのアーキテクチャルスタイルです。GET、POST、PUT、DELETEなどの標準HTTPメソッドを使用してCRUD操作を実行します。RESTはそのシンプルさと広範な採用で知られています。
RESTの制限事項:
- データのオーバーフェッチングまたはアンダーフェッチング。
- 変更を受け入れるために複数のエンドポイントとバージョニングが必要。
- 組み込みのリアルタイム機能がない。
GraphQLとREST API:違いは何ですか?
GraphQLとRESTは、APIを構築するための2つの人気のあるアプローチであり、それぞれに強みがあります。RESTが長年の標準であったのに対し、GraphQLは特にデータの取得とフロントエンドとバックエンドチームの間の協力の柔軟性と効率性を提供します。
主な違い
- RESTは複数のエンドポイントを使用し、変更に対応するためにバージョニングが必要ですが、GraphQLはデータの取得を単一のクエリに統合し、クライアントがデータ要件を指定するため、バージョニングの必要性を減らします。
- RESTは成功またはエラーを示すためにHTTPステータスコードを使用しますが、GraphQLは常に200 OKステータスを返し、エラーをレスポンスボディで通知します。
- GraphQLは、RESTに欠けている組み込みのリアルタイムサポートをサブスクリプションを通じてサポートします。
- RESTは多くのツールと確立しているが、GraphQLの環境は急速に成長し、GraphiQLのような強力なツールを提供しており、開発が容易になっています。
- 最後に、RESTはキャッシュのためにヘッダーを使用しますが、動的クエリのためにGraphQLはより高度なテクニックを必要としますが、効率的なキャッシングのために永続クエリのようなオプションを提供しています。
コアGraphQLコンセプト
1. スキーマ定義言語(SDL)
GraphQLには独自のタイプシステムがあり、APIのスキーマを定義するために使用されます。スキーマを記述する構文はスキーマ定義言語(SDL)と呼ばれます。
2. クエリ vs ミューテーション vs サブスクリプション
- クエリはサーバーからデータを取得するために使用されます。RESTが複数の固定エンドポイントを使用するのとは異なり、GraphQLは単一のエンドポイントを使用し、クライアントがクエリで必要なデータを指定します。これにより柔軟性が提供されます。
- ミューテーションはサーバー上のデータを変更するために使用され、データの作成、更新、削除などを行います。これによりクライアントは変更をバックエンドに送信でき、データを書き込む必要があるアプリケーションには欠かせない機能です。
- サブスクリプションはクライアントとサーバーの間で確立された接続を維持することでリアルタイムの更新を可能にします。サブスクライブされたイベントが発生すると、サーバーは更新をプッシュしてクライアントに提供し、クエリやミューテーションとは異なり、リクエスト-レスポンスのサイクルに従わず連続的なデータストリームを提供します。
3. GraphQLスキーマ
データ構造を定義し、クエリや変更が可能であり、サーバーとクライアント間の契約として機能します。クライアントがアクセスできるタイプ、フィールド、および関係を指定します。スキーマには通常、データ取得のための特別なルートタイプが含まれます:データを取得するためのQuery、データを変更するためのMutation、リアルタイム更新のためのSubscriptionです。これらのタイプは、APIの機能とクライアントがそれとどのように相互作用できるかを定義します。
4. リゾルバ:GraphQLクエリをデータにマッピングする
リゾルバは、GraphQLサーバーでデータを取得するためのロジックを処理する関数です。スキーマ内の各フィールドはリゾルバにリンクされており、そのフィールドのデータを取得または計算する方法を決定します。クエリが実行されると、サーバーはリクエストされたフィールドに対して適切なリゾルバを呼び出します。リゾルバはスカラーまたはオブジェクトを返すことができ、オブジェクトが返された場合は子フィールドの実行が続き、スカラーが返された場合は完了します。nullが返された場合は、実行が停止します。リゾルバは、GraphQLクエリを実際のデータソースにマッピングするために不可欠です。
JavaにおけるGraphQLの利点
- 正確なデータ取得:必要なデータのみをクエリし、それ以上は取得せず、予測可能で効率的な結果を保証します。
- 複数リソースの単一リクエスト:一つのクエリで関連データを取得し、複数のAPI呼び出しを減らします。
- 型システム:APIを型とフィールドで整理し、クエリが有効でエラーが明確であることを保証します。
- 開発者ツール:GraphiQLのようなツールを使用して生産性を向上させ、型定義を用いてより良いクエリビルディングとデバッグを行います。
- バージョンレス進化:既存のクエリを壊さずにフィールドを追加または廃止し、APIを保守可能な状態に保つ。
- 柔軟なデータ統合:既存のデータとコードに対して統一されたAPIを作成し、さまざまなストレージエンジンや言語と互換性のあるものにする。
JavaでGraphQL APIを設定する
実例:ユーザーと注文
大規模な組織向けの従業員ディレクトリAPIを構築していると想像してください。クライアントが従業員の名前、役職、部署、さらには報告階層などの詳細をクエリできるようにすることが目標です。
1. プロジェクトの設定
Spring Tool Suiteを使用して新しいSpring Bootプロジェクトを作成するか、Spring Initialiserに移動します。その後、これらの依存関係をpom.xml
ファイルに追加します:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-graphql</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.graphql</groupId>
<artifactId>spring-graphql-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2. エンティティを作成
GraphQLを介してクエリまたは変更されるデータを表すJavaエンティティ(例:User
およびOrder
)を作成します。たとえば:
public class User {
strategy = GenerationType.IDENTITY) (
private Long userId;
private String name;
private String email;
private String password;
// Getters and setters...
}
public class Order {
strategy = GenerationType.IDENTITY) (
private Long orderId;
private String orderDetails;
private String address;
private int price;
private User user;
// Getters and setters...
}
3. リポジトリを作成
データベースとやり取りするためのリポジトリを作成します:
public interface UserRepository extends JpaRepository<User, Long> {}
public interface OrderRepository extends JpaRepository<Order, Long> {}
4. サービスクラスを作成
ビジネスロジックを処理するサービスクラスを作成します:
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User createUser(User user) {
return userRepository.save(user);
}
public User getUser(Long userId) {
return userRepository.findById(userId).orElseThrow(() -> new RuntimeException("User not found"));
}
public List<User> getAllUsers() {
return userRepository.findAll();
}
public boolean deleteUser(Long userId) {
userRepository.deleteById(userId);
return true;
}
}
5. GraphQLコントローラーを作成する
クエリとミューテーションを処理するGraphQLコントローラーを定義します:
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
public List<User> getUsers() {
return userService.getAllUsers();
}
public User getUser( Long userId) {
return userService.getUser(userId);
}
public User createUser( String name, String email, String password) {
User user = new User();
user.setName(name);
user.setEmail(email);
user.setPassword(password);
return userService.createUser(user);
}
public boolean deleteUser( Long userId) {
return userService.deleteUser(userId);
}
}
6. GraphQLスキーマを定義する
src/main/resources
ディレクトリにschema.graphqls
ファイルを作成します:
type User {
userId: ID!
name: String
email: String
password: String
}
type Query {
getUsers: [User]
getUser(userId: ID!): User
}
type Mutation {
createUser(name: String, email: String, password: String): User
deleteUser(userId: ID!): Boolean
}
7. application.propertiesでGraphQLを設定する
オプションで、scr/main/resources/application.properties
にGraphQL設定を構成します:
spring.graphql.graphiql.enabled=true
8. アプリケーションを実行する
mvn spring-boot:run
またはIDEからSpringBootアプリケーションを実行します。実行中は、/graphiql
でGraphALエンドポイントにアクセスできます。
9. GraphQLクエリでテストする
GraphQL APIをGraphiQLやPostmanなどのツールを使ってテストします。
ミューテーションの場合:
mutation {
createUser(
name:"swetha",
email:"[email protected]",
password:"23sde4dfg43"
){
name,
userId
}
}
出力:
{
"data": {
"createUser": {
"name": "swetha",
"userId": "3"
}
}
}
クエリの場合:
query{
getUsers{
name
}
}
出力:
{
"data": {
"getUsers": [
{
"name": "Medha"
},
{
"name": "Riya"
},
{
"name": "swetha"
}
]
}
}
高度なGraphQL機能
1. フラグメントによる再利用性の向上
フラグメントは、特定の型のために定義された再利用可能なフィールドのセットです。これは、GraphQLコードの構造と再利用性を向上させるのに役立つ機能です。
2. 引数でフィールドをパラメータ化する
GraphQLでは、フィールドは引数を受け入れることができ、クエリをより動的かつ柔軟にします。これらの引数を使用すると、APIによって返されるデータをフィルタリングしたりカスタマイズしたりすることができます。
3. GraphQLでのページネーションとソート
ページネーション
ページネーションはAPI設計における難しいトピックです。大まかに言うと、それを取り組む方法については2つの主要なアプローチがあります。
- リミットオフセット:取得するアイテムのインデックスを提供することで、リストの特定のチャンクをリクエストします(実際には、開始インデックス(オフセット)と取得するアイテムの数(制限)をほとんど提供しています)。
- カーソルベース:このページネーションモデルは少し高度です。リスト内のすべての要素は一意のID(カーソル)と関連付けられています。その後、リストをページ送りするクライアントは、開始要素のカーソルと取得するアイテムの数を提供します。
ソート
GraphQL APIデザインでは、特定の基準に従ってソートされた要素のリストを返すことが可能です。順序付けに基づく)
GraphQLの使用に関する課題と考慮事項
- 複雑さ:単純なデータモデルや経験の浅いチームにとって、GraphQLスキーマとクエリの管理は課題となる場合があります。
- パフォーマンスの問題:深くネストされたクエリは最適化されていない場合、バックエンドリソースを圧迫する可能性があります。
- キャッシュの課題:標準のRESTベースのキャッシュ戦略は適用されず、カスタムソリューションが必要です。
- セキュリティの懸念: 過剰取得や悪意のあるクエリには、クエリ制限やその他の安全策が必要です。
- ハイブリッド使用: 複雑なデータニーズに最適で、シンプルな操作のためにRESTと組み合わせることがよくあります。
結論
GraphQLは、Javaで現代のAPIを構築するための柔軟で効率的なアプローチを提供し、動的でデータ集約型のアプリケーションに最適な選択肢となります。その単一エンドポイントアーキテクチャと強い型付けは、API設計を簡素化し、堅牢なパフォーマンスを確保します。シンプルな従業員ディレクトリを作成する場合でも、複雑な分析プラットフォームを構築する場合でも、GraphQLは開発者にスケーラブルなソリューションを簡単に提供する力を与えます。Spring Bootやgraphql-java
のようなツールを使って、次のプロジェクトでGraphQLの可能性を最大限に引き出すために、今日からGraphQLを探求し始めましょう。
ソースコード
このチュートリアルの完全なソースコードはGithubで見つけることができます。
Source:
https://dzone.com/articles/design-scalable-java-apis-with-graphql