banner
Violet

Violet's Blog

A Web <Developer />. Code_ for Fun.
x
github
bilibili
email

初めてのGraphQL使用

本文首次发布于我的博客,原文地址vio.vin/article/use-puppeteer

GraphQL API は Restful API に似ており、データをクエリするための言語です。Restful API と比較して、GraphQL API はクエリにおいてより柔軟で、フロントエンドとバックエンドのコード作成もより便利です。本記事では、SpringBoot3.0 を基に GraphQL API アプリケーションを構築する方法、GraphQL API インターフェースが利用可能かどうかをテストする方法、そしてフロントエンドが GraphQL API インターフェースをどのように呼び出すか(Nuxt プロジェクトを例に)を紹介します。

GraphQL とは#

以下の内容はGraphQL Wikiからの抜粋です。

GraphQL はオープンソースの API 向けに作成されたデータクエリ操作言語およびそれに対応する実行環境です。2012 年に Facebook 内部で開発されていたが、2015 年に公開されました。2018 年 11 月 7 日、Facebook は GraphQL プロジェクトを新設された GraphQL 基金(非営利の Linux 基金に属する)に移管しました。

GraphQL は REST や他の Web サービスアーキテクチャに比べて、Web API を開発するためのより効率的で強力かつ柔軟な方法を提供します。クライアントが必要に応じてデータ構造を定義し、サーバーが同じデータ構造の対応データを返すことで、サーバーからの冗長なデータの返却を避けますが、一方でこの方法はクエリ結果の Web キャッシュを効果的に利用できないことを意味します。GraphQL のクエリ言語がもたらす柔軟性と豊かさは同時に複雑さを増し、シンプルな API がこの方法に適さない可能性があります。

なぜ GraphQL を使用するのか#

  • フロントエンドがどのデータを返すかを決定します。これはバックエンドが複雑な形式の JSON を必要とする場合に特に便利で、フロントエンドは必要なデータと不要なデータを自分で決定し、冗長なデータを減らし、バックエンドの負担を軽減します。
  • クエリだけでなく、更新にも使用できます。名前は Graph Query Language ですが、GraphQL は作成、更新、削除操作にも使用できます。

使用方法#

GraphQL インターフェースを呼び出して、バックエンドにこのようなデータを送信します。これは JSON ではないことに注意してください。

ここで渡されるパラメータは記事の ID であり、特定の記事をクエリするために使用されます。

query Article {
  article(id: "2") {
    id
    title
    content
    author {
      id
      firstName
      lastName
    }
    tags {
      id
      name
      description
    }
  }
}

バックエンドはリクエスト内のデータ構造に基づいて対応するデータを返します。

{
  "data": {
    "article": {
      "id": "2",
      "title": "title2",
      "content": "content2",
      "author": {
        "id": "author-2",
        "firstName": "Douglas",
        "lastName": "Adams"
      },
      "tags": [
        {
          "id": "2",
          "name": "Python",
          "description": "Python関連の記事"
        },
        {
          "id": "3",
          "name": "JavaScript",
          "description": "JavaScript関連の記事"
        }
      ]
    }
  }
}

複数のデータを一度にクエリすることもできます。

query Article {
  articles {
    id
    title
    content
    author {
      id
      firstName
      lastName
    }
    tags {
      id
      name
      description
    }
  }
}

Reponse

{
  "data": {
    "articles": [
      {
        "id": "1",
        "title": "title1",
        "content": "content1",
        "author": {
          "id": "author-1",
          "firstName": "Joshua",
          "lastName": "Bloch"
        },
        "tags": [
          {
            "id": "1",
            "name": "Java",
            "description": "Java関連の記事"
          },
          {
            "id": "2",
            "name": "Python",
            "description": "Python関連の記事"
          },
          {
            "id": "1",
            "name": "Java",
            "description": "Java関連の記事"
          }
        ]
      },
      {
        "id": "2",
        "title": "title2",
        "content": "content2",
        "author": {
          "id": "author-2",
          "firstName": "Douglas",
          "lastName": "Adams"
        },
        "tags": [
          {
            "id": "2",
            "name": "Python",
            "description": "Python関連の記事"
          },
          {
            "id": "3",
            "name": "JavaScript",
            "description": "JavaScript関連の記事"
          }
        ]
      }
    ]
  }
}

SpringBoot アプリケーションの構築#

IDEA に GraphQL 関連のプラグインを先にインストールすることをお勧めします。GraphQLこのプラグインはschema.graphqlsファイルの構文ハイライトをサポートします。

プロジェクトの作成#

pom.xml に以下の依存関係を追加する必要があります。

<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>

エンティティクラスの定義#

エンティティクラスはデータベースのフィールドに対応することも、自作の VO であることもできます。ここでは record を使用していますが、従来の class を使用することも選択できます。

public record Article(String id, String title, String content, String authorId, String tagId) {}

public record Author (String id, String firstName, String lastName) {}

public record Tag(String id, String name, String description) {}

データのクエリ#

schema.graphqlsの定義#

schema.graphqlsファイルは GraphQL スキーマを定義し、データ構造とデータ間の関係、クライアントが行える操作を記述するために使用されます。
ファイルは以下の内容を定義します。

  • タイプ
  • クエリ
  • 関係

以下は具体的なschema.graphqlsファイルの例です。

# クエリのインターフェース、クライアントがアクセスできる内容
type Query {
    # idはクエリのパラメータを示し、Articleは下のtypeで定義された返却データ構造です
    article(id: String): Article
    # [Article]を使用して多くのデータが配列形式で返されることを示します
    articles: [Article]
    tag(id: String): Tag
    tags: [Tag]
    author(id: String): Author
}

# データ構造の定義
type Author {
    id: String
    firstName: String
    lastName: String
}

# tagsは複数のデータを持つため、[Tag]で示します
type Article {
    id: String
    title: String
    content: String
    author: Author
    tags: [Tag]
}

type Tag {
    id: String
    name: String
    description: String
}

コントローラーの作成#

GraphQL もコントローラーを通じてアクセスする必要があります。MVC で@RequsetMappingを使用するのに対し、GraphQL では@QueryMappingを使用する必要があります。この@QueryMappingはリクエストパスを定義する必要がありません。以下は具体的な例です。

@QueryMapping#

@QueryMapping
public Collection<Article> articles()
{
    return queryService.listArticles();
}

ここでのメソッド名はarticles()で、schema.graphqlsファイルのtype Queryで定義された名前と一致する必要があります。

フロントエンドが
query Article { articles { id } }を送信すると、このインターフェースにマッチします。このメソッドはtype Articleに含まれるすべての属性を返し、その後GraphQLはフロントエンドから渡されたパラメータに基づいて必要なデータを自動的に保持します。

例えば、この例ではフロントエンドが id と title だけをリクエストしたため、id と title のみが返され、他のデータは隠されます / 削除されます。

query Article {
  articles {
    id
    title
  }
}

クエリのパラメータには@Argument注釈を追加する必要があります。さもなければエラーが発生します。

@QueryMapping
public Article article(@Argument String id) {
    return queryService.getArticleById(id);
}

@SchemaMapping#

@QueryMapping@SchemaMappingは GraphQL の最も重要な 2 つの注釈です。@QueryMappingはリクエストアドレスをマッチさせるために使用され、@SchemaMappingはデータ関係を構築するために使用されます。

具体的な例を挙げると、

@QueryMapping
public Article article(@Argument String id) {
    return queryService.getArticleById(id);
}

@SchemaMapping
public Collection<Tag> tags(Article article)
{
    return queryService.getTagsByArticleId(article.id());
}

@SchemaMapping
public Author author(Article article)
{
    return queryService.getAuthorByAuthorId(article.authorId());
}

tags()メソッドは Article に関連する Tag をクエリするために使用されるため、メソッドのパラメータはArticle articleであり、返却データは複数の Tag です。同様に、author は Article に関連する Author をクエリするために使用され、返却データは Author 型です。

データの保存#

schema.graphqlsの定義#

type Mutation {
    # !はこのパラメータが必須であることを示し、:Articleは挿入後に返されるデータ型を示します
    createArticle(article: ArticleInput!): Article
}

input ArticleInput {
    title: String
    content: String
    authorId: String
    tagId: String
}

コントローラー#

@MutationMapping
public Article createArticle(@Argument("article") ArticleInput article) {
    return createService.createArticle(article);
}

このインターフェースを呼び出す#

mutation {
  createArticle(
    article: {title: "Sample Title", content: "Sample Content", authorId: "author-3", tagId: "2"}
  ) {
    id
    title
    content
    author {
      id
      firstName
      lastName
    }
    tags {
      id
      name
      description
    }
  }
}

データの削除 / 更新#

データの削除もMutation内で操作を定義する必要があります。: の後は操作が完了した後の返却型です。ここでは詳細には説明しません。

type Mutation {
    deleteArticle(id: String!): Boolean
    updateArticle(id: String!, article: ArticleInput!): Article
}

バックエンドプロジェクトのアドレスhttps://github.com/lnbiuc/graphql-start

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。