GraphQL APIを構築するには?

GraphQLカバーとは

近年、GraphQLは複雑なAPIを構築するための一般的な選択肢となっています。これは、従来のREST APIの制限のいくつかを排除し、APIをより柔軟で効率的にするためです。

この記事では、GraphQLについて、その利点と欠点、主要なGraphQL用語、GraphQL APIとREST APIの比較について説明します。さらに、Back4appで独自のGraphQL APIを構築し、Next.jsのフロントエンドから接続する方法も紹介します。

GraphQL入門

GraphQLは、アプリケーション・プログラミング・インターフェース(API)を開発するためのクエリー言語であり、サーバーサイドのランタイムです。GraphQLを使用すると、クライアントはバックエンドが提供する固定されたデータセットに依存するのではなく、APIから必要なデータを正確に指定することができます。

GraphQLは、高速で柔軟なAPIを構築するためのモダンで効率的なアプローチである。型システムが組み込まれており、APIを通じて利用可能なデータを定義する強く型付けされたスキーマに基づいている。リアルタイム更新とサブスクリプションをサポートし、開発者は複数のデータソースからデータを取得することができる。その上、既存のクエリーや変異に影響を与えることなくフィールドを非推奨にする機能を開発者に提供することで、APIを簡単に進化させることができる。

GraphQLはプロジェクトの最初から使用することも、既存のAPIに統合することもできる。また、RESTと組み合わせて段階的に移行する企業もある。

2012年にFacebook社内で開発され、その後2015年にオープンソース化された。GraphQLはシングルページアプリケーション(SPA)やモバイルアプリの台頭とともに人気を博してきた。リリース以来、GitHub、Airbnb、Pinterest、Shopifyなど多くの技術大手によって採用されている。

GraphQLとRESTの比較

GraphQLとRESTは、ウェブAPIを構築するための2つの一般的なアプローチである。

REST(Representational State Transfer)は、ウェブの構造を記述するソフトウェア・アーキテクチャ・スタイルである。2000年に導入され、10年以上にわたってウェブAPI構築のデファクトスタンダードとなっている。GETPOSTPUTPATCHDELETEといったHTTPメソッドを利用してリソースを操作する。各リソースはエンドポイントにホストされ(下の画像を見てほしい)、リソースをリクエストするたびに「データセット」全体が返される。

このアーキテクチャには2つの問題があった。1つ目は、フェッチ不足(取得するデータが少なすぎる)とフェッチ過多(取得するデータが多すぎる)だ。さらに、REST APIではデータの変更を購読することができない。

そこで登場するのがGraphQLだ。GraphQLは単一のエンドポイントを持ち、1回のリクエストで複数のデータソースからデータを照会できる。必要なデータを正確に定義することができる。さらに、GraphQLはサーバーをポーリングすることなくデータの変更をサブスクライブすることを可能にする。これにより、APIはより予測しやすくなり、自己文書化される。

結局のところ、GraphQLとRESTのどちらを選ぶかは、プロジェクトの具体的な要件による。たとえGraphQLが素晴らしくても、単純なプロジェクトにとっては複雑すぎるかもしれない。

REST APIとGraphQL APIの比較

一般的なGraphQL用語

GraphQLを使用する際に遭遇する可能性のある一般的な用語をいくつか見てみましょう。

タイプ

GraphQLには型システムがあり、強く型付けされています。IntFloatStringBooleanなどのスカラー型が組み込まれていますが、カスタム型を定義することもできます。

カスタム・タイプはこのように定義できる:

type User {
    username: String!
    password: String!
    friends: [User!]
}

スキーマ

スキーマとは、GraphQL APIを通じて利用可能なデータの記述です。オブジェクトタイプ、フィールド、関連データ型、リレーションシップ、クエリ、変異などが含まれます。スキーマは通常、スキーマ定義言語(SDL)を使用して定義されます。

スキーマの例

リゾルバ

リゾルバは、GraphQLクエリの特定のフィールドのデータを取得する関数です。リゾルバ関数は、データソースからデータを取得し、それを期待される形式で返す役割を担っています。

クエリー

クエリとは、GraphQL APIからのデータに対する読み取り専用のリクエストです。クエリーはREST APIにおけるGETリクエストと考えることができます。

query GetUser {
    user(id: "Wfx8o2AZrE") {
        id
        username
        fullName
    }
}

このクエリーは、すべてのユーザーのリストを返します。

突然変異

変異は、GraphQL APIでデータを操作するためのリクエストです。変異はREST APIにおけるPOST/PUT/PATCH/DELETEリクエストと考えることができます。変異は、どのようなデータが返されるかを定義することもできます。

mutation CreateAuthor {
  createAuthor(input: {fields: {firstName: "William", lastName: "Shakespeare"}}) {
    author {
      id
      createdAt
    }
  }
}

この変異は新しい著者を作成し、著者のidと createdAtを返します。

サブスクリプション

サブスクリプションは、GraphQL APIからのリアルタイムの更新のリクエストです。サブスクリプションにより、クライアントはサーバーをポーリングすることなく、アップデートが利用可能になるとすぐに受け取ることができます。

subscription OnPostCreate($postID: ID!) {
  userAdded(postID: $postID) {
    id
    user
    content
  }
}

このサブスクリプションは新しい投稿が作成されたときに呼び出されます。

GraphQLはどのように機能するのか?

GraphQL APIを実装するには、以下の手順を実行する必要がある:

  1. スキーマを使ってデータを記述する
  2. リゾルバをデータソースに接続する
  3. クエリーと突然変異を書く
  4. 予測可能な結果を得る

Back4appや同様のサービスを利用することで、この作業のほとんどが抽象化される。データベースモデルを作成すると、Back4appが自動的にGraphQLスキーマとドキュメントを生成します。これについてはチュートリアルの実践編で詳しく説明する。

GraphQLの利点は何ですか?

GraphQLは習得が簡単で、ユーザーは複数のソースからデータを集約でき、APIのためのモダンな言語だ。

スキーマ

GraphQL APIは強く型付けされたスキーマに基づいています。これにより、実行時ではなくコンパイル時に型エラーやバグを検出することができます。さらに、GraphQL APIは内省的であり、外部ドキュメントに依存することなく自分自身に関する情報を提供できることを意味します。

柔軟で効率的なデータ・フェッチ

GraphQL APIは、クライアントが必要なものを正確に指定できるため、非常に柔軟である。これにより、アンダーフェッチやオーバーフェッチの問題を解決し、APIリクエストの数を減らすことができます。APIリクエスト数が減れば、パフォーマンスが向上します。

APIアップデート

GraphQLを使用すると、現在のクエリに影響を与えることなく、新しいフィールドやタイプをシームレスに統合できます。非推奨のフィールドや古いフィールドはツールから隠すこともできます。GraphQL APIはアプリに新機能への絶え間ないアクセスを提供し、よりクリーンで持続可能なサーバーコードの開発を促します。

真実の単一ソース

GraphQLスキーマは、GraphQLアプリケーションにおける単一の真実のソースを設定します。これは組織にAPI全体を管理する簡単な方法を提供する。

GraphQLエクステンション

GraphQLはGraphQL開発者の巨大なコミュニティに支えられており、多くのオープンソースの拡張機能が付属している。拡張機能は、ページネーション、キャッシュ、パフォーマンス監視など、一般的なAPIタスクのいくつかを簡素化する。

GraphQLの欠点は何ですか?

複雑さ

GraphQLはデータクエリの作業の多くをサーバーサイドにシフトさせ、バックエンドをより複雑にする。その上、クエリ言語とスキーマの定義には、より前もっての計画とメンテナンスが必要になるかもしれない。

学習曲線

GraphQLはRESTよりも学習曲線が急です。さらに、GraphQLの開発者は通常RESTの開発者よりも高価で、見つけるのが難しい。

標準化の欠如

GraphQLの主な批判のひとつは、その実装における標準化の欠如である。REST APIには確立された原則とベストプラクティスのセットがある一方で、GraphQLのドキュメントには実装方法に関する一般的なヒントしか記載されていません。これは、GraphQL APIの設計方法や使用方法において矛盾や混乱を招く可能性があります。

セキュリティ

GraphQLの素晴らしい点は、クライアントが必要なものを正確にリクエストできることですが、一方でそれは潜在的なセキュリティリスクとなり得ます。悪意のあるクエリが実行されないように、ユーザー入力を適切に検証し、サニタイズすることが重要です。

GraphQL APIを構築するには?

このセクションでは、Back4appで GraphQL APIを作成し、Next.jsのフロントエンドから接続する方法を紹介します。

前提条件

  • JavaScript ES6の使用経験
  • ReactとNext.jsの使用経験
  • GraphQLの基本的な理解

Back4appとは?

Back4appは、オープンソースソフトウェア上で動作する優れたBaaS(Backend as a Service)ソリューションです。このプラットフォームは、ウェブアプリケーションやモバイルアプリケーションをより簡単かつ迅速に開発するための幅広い機能を提供します。これにより、企業はバックエンドや基盤となるインフラを気にすることなく、ビジネスロジックに集中することができます。

Back4appは、機能満載の使いやすいダッシュボードとコマンドラインインターフェイス(CLI)を備えている。また、Node.js、Flutter、React Native、Android、Angular、iOSなど様々な人気ツール用のソフトウェア開発キット(SDK)も提供している。

Back4appは、どのようなアプリのニーズにも応えることができる分かりやすい価格設定モデルを採用している。また、テストやプロトタイピングに最適な無料プラン(クレジットカード不要)も提供している。

Back4appについてもっと知りたいですか?Back4appを使う理由をご覧ください。

プロジェクト紹介

私たちはシンプルなウェブTODOアプリケーションを構築します。アプリはバックエンドとフロントエンドの2つの部分で構成される。バックエンドはGraphQL APIで動作し、Back4appにデプロイされます。一方フロントエンドは、Next.jsフレームワークを使用してTypeScriptで記述します。フロントエンドとバックエンドの接続にはApollo Clientを使用する。

最終的なアプリケーションはこのようになる:

back4app-graphqlプロジェクト・プレビュー

バックエンド

Back4appアプリの作成

次のステップに進むには、Back4appアカウントが必要です。すでにお持ちの場合は、ログインしてください。そうでない場合は、無料アカウントにご登録ください。

Back4appを利用するには、まずアプリを作成する必要があります。ダッシュボードにログインすると、現在のアプリの一覧が表示されます。新しいアプリを作成するには、”Build a new app “をクリックしてください。

Back4appアプリ作成

GraphQL APIを構築するので、”Backend as a Service “オプションを選択し、アプリの一意の名前を指定する。さらに、データベースのタイプとして “NoSQL “を選択する。

Back4appが、データベース、アプリケーションレイヤー、スケーリング、バックアップ、セキュリティなど、アプリに必要なすべての設定を行うのを辛抱強く待ちましょう。

セットアップが完了すると、アプリのダッシュボードが表示されます。

Back4appアプリ作成

データベース・モデルの定義

今回はシンプルなTODOアプリを作るので、データベース・モデルは1つで十分です。

まず、Back4appのダッシュボードに行き、サイドバーにある “Database “オプションを探してください。そこから “Create a class “を選択し、”Task “という名前を付けます。Public Read and Write Enabled “を選択し、”Create class & add columns “をクリックしてください。

Back4appの定義モデル

それに続く列を含む:

+-----------+------------------+---------------+----------+
| Data type | Name             | Default value | Required |
+-----------+------------------+---------------+----------+
| String    | name             | <leave blank> | yes      |
+-----------+------------------+---------------+----------+
| String    | description      | <leave blank> | no       |
+-----------+------------------+---------------+----------+
| Boolean   | isDone           | false         | no       |
+-----------+------------------+---------------+----------+

データベースモデルを作成した後、4つのデータベースカラムが自動的に追加されていることに気づくでしょう:

  1. objectIdはオブジェクトの主キーです。
  2. updatedAtは最終更新のタイムスタンプ。
  3. createdAtは作成時のタイムスタンプです。
  4. ACLは“アクセス・コントロール・リスト “を定義する。

チュートリアルの後半でGraphQLクエリやミューテーションを行う際に必要になるので、覚えておきましょう。

Back4appのダッシュボードに慣れるために、2つのサンプルタスクを追加してみてください:

+-----------------+----------------------------------------+--------+
| name            | description                            | isDone |
+-----------------+----------------------------------------+--------+
| GraphQL backend | Create a GraphQL backend via Back4app. | false  |
+-----------------+----------------------------------------+--------+
| Learn GraphQL   | Learn the basics of GraphQL.           | true   |
+-----------------+----------------------------------------+--------+

GraphQL API コンソール

GraphQL API Consoleを使用すると、コードに実装する前にGraphQLクエリやミューテーションをテストすることができます。コンソールにアクセスするには、サイドバーで「API」を選択し、「Console > GraphQL」を選択します。

Back4app GraphQL コンソール

コンソールは非常に使いやすい。左側にカスタムクエリとミューテーションを入力し、右側に結果が表示されます。

すべてが機能しているかどうかを確認するには、次のクエリーを実行する:

query CheckHealth {
    health
}

以下のようなJSONレスポンスが返ってくるはずだ:

{
  "data": {
    "health": true
  }
}

Back4appの素晴らしい点の一つは、Parseをベースにしていることだ。データベースモデルを作成すると、Parseが自動的にGraphQLを設定してくれた。これにはGraphQLスキーマやドキュメントの生成などが含まれる。

データベースからタスクとその詳細をリストアップしてみよう:

query GetTasks {
  tasks {
    count
    edges {
      node {
        id
        name
        description
        isDone
      }
    }
  }
}

同じような反応が返ってくるはずだ:

{
  "data": {
    "tasks": {
      "count": 2,
      "edges": [
        {
          "node": {
            "id": "VGFzazpXQkJzSkRtV2xU",
            "name": "GraphQL backend",
            "description": "Create a GraphQL backend via Back4app.",
            "isDone": false
          }
        },
        {
          "node": {
            "id": "VGFzazpnM2lhNzdwUXBp",
            "name": "Learn GraphQL",
            "description": "Learn the basics of GraphQL.",
            "isDone": true
          }
        }
      ]
    }
  }
}

特定のオブジェクトを取得したり、オブジェクトを作成したり、更新したりするのも同様だ。これらのクエリや変異についてはチュートリアルの後半で説明するので、今はあまり詳しく説明しません。さらに、Back4appのドキュメントがこれらのトピックをよくカバーしています:

  1. オブジェクトの作成
  2. オブジェクトの取得
  3. オブジェクトの検索
  4. オブジェクトの更新
  5. オブジェクトの削除
  6. 認証

バックエンドの部分は以上です。次のセクションでは、フロントエンドに取りかかります。

フロントエンド

次のアプリを作成する

Next.jsプロジェクトをブートストラップする最も簡単な方法は、create-next-appユーティリティを使うことです。ターミナルを開き、次のコマンドを実行してください:

$ yarn create next-app

√ What is your project named? ... back4app-graphql
√ Would you like to use TypeScript with this project? ... No
√ Would you like to use ESLint with this project? ... Yes
√ Would you like to use the `src/` directory with this project? ... No
√ Would you like to use the experimental `app/` directory with this project? ... No
√ What import alias would you like configured? ... @/*

Successfully created a Next.js app.

次に、開発サーバーを実行する:

$ yarn dev

http://localhost:3000。デフォルトのNext.jsランディングページが表示されます。

NextJSデフォルトのランディングページ

ChakraUI

UI/UXの構築プロセスを加速し簡素化するために、ChakraUIを使用します。Chakra UIは、Reactアプリの構築に必要なすべてを提供する、シンプルでモジュール化されたアクセス可能なコンポーネント・ライブラリです。

問題が発生した場合は、ChakraUIを参照してください:Next.jsを使い始める

インストールするには

yarn add @chakra-ui/react @emotion/react @emotion/styled framer-motion

次に、_pages/app.tsxに移動し、ChakraProviderでアプリを次のようにラップします:

// pages/_app.tsx

import "../styles/globals.css";
import type {AppProps} from "next/app";
import {ChakraProvider} from "@chakra-ui/react";

export const theme = extendTheme({});

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <ChakraProvider theme={theme}>
      <Component {...pageProps} />
    </ChakraProvider>
  );
}

export default MyApp;

ChakraProviderのインポートをお忘れなく:

import {ChakraProvider} from "@chakra-ui/provider";

不規則な色の点滅を避けるには、コンテンツの前にカラーモードのスクリプトを読み込むようにしてください。そのためには、_document.jsを次のように利用します:

// pages/_document.tsx

import {ColorModeScript} from "@chakra-ui/react";
import { Html, Head, Main, NextScript } from "next/document";
import {theme} from "@/pages/_app";

export default function Document() {
  return (
    <Html lang='en'>
      <Head />
      <body>
        <ColorModeScript initialColorMode={theme.config.initialColorMode} />
        <Main />
        <NextScript />
      </body>
    </Html>
  );
}

ChakraUIのインストールが完了しました。

ユーザーインターフェース

続いて、ユーザー・インターフェースを作りましょう。私たちのウェブ・アプリには、以下の2つのページがあります:

  1. / タスクのリストを表示する
  2. create/タスクを作成するフォームを表示します。

まず、pages/index.tsxを以下の内容に置き換える:

// pages/index.tsx

import type {NextPage} from "next";
import {
    Button, Card, CardBody, Container,
    Heading, HStack, Stack, Text, VStack
} from "@chakra-ui/react";
import Link from "next/link";

let data = {
  "tasks": {
    "count": 2,
    "edges": [
      {
        "node": {
          "id": "VGFzazpXQkJzSkRtV2xU",
          "name": "GraphQL backend",
          "description": "Create a GraphQL backend via Back4app.",
          "isDone": false
        }
      },
      {
        "node": {
          "id": "VGFzazpnM2lhNzdwUXBp",
          "name": "Learn GraphQL",
          "description": "Learn the basics of GraphQL.",
          "isDone": true
        }
      }
    ]
  }
};

const ListPage: NextPage = () => {

  const handleMarkAsDone = async (id: string, isDone: boolean) => {
    console.log("TODO: mark task as done and refetch");
  };

  const handleDelete = async (id: string) => {
    console.log("TODO: delete task and refetch");
  };

  return (
    <>
      <Container maxWidth="container.lg">
        <HStack w="fill" justifyContent="space-between" mt={8} mb={4}>
          <Heading as="h1" size="lg">back4app-graphql</Heading>
          <Link href="/create">
            <Button size="sm" colorScheme="blue">
              Create task
            </Button>
          </Link>
        </HStack>
        <VStack spacing={4}>
          {data.tasks.edges.map((edge) => {
            let task = edge.node;
            return (
              <Card key={task.id} w="100%">
                <CardBody>
                  <Stack direction="column">
                    <Heading as="h2" size="md">
                      {task.isDone ? "✔️" : "❌"}{" "}
                      {task.name}
                    </Heading>
                    <Text>
                      {task.description}
                    </Text>
                    <Stack direction="row" pt={2}>
                      <Button size="sm" colorScheme="blue" onClick={() => handleMarkAsDone(task.id, task.isDone)}>
                        Toggle done
                      </Button>
                      <Button size="sm" colorScheme="red" onClick={() => handleDelete(task.id)}>
                        Delete
                      </Button>
                    </Stack>
                  </Stack>
                </CardBody>
              </Card>
            );
          })}
        </VStack>
      </Container>
    </>
  );
};

export default ListPage;
  1. ユーザーインターフェースのデザインにはChakraUIを使用しました。
  2. タスクは現在、dataという静的配列からロードされている。
  3. 後でhandleMarkAsDone()handleDelete()を利用して、GraphQL APIリクエストを送信する。

次に、pagesフォルダ内に以下の内容でcreate.tsxファイルを作成する:

// pages/create.tsx

import type {NextPage} from "next";
import {
  Button, Card, CardBody, CardHeader, Container, FormControl,
  FormLabel, Heading, HStack, Input, Stack, Switch, Text
} from "@chakra-ui/react";
import Link from "next/link";
import {useState} from "react";
import {useRouter} from "next/router";

const CreatePage: NextPage = () => {
  const router = useRouter();

  const [name, setName] = useState("");
  const [description, setDescription] = useState("");
  const [isDone, setIsDone] = useState(false);

  const [formError, setFormError] = useState("");

  const handleSubmit = (event) => {
    event.preventDefault();

    if (!name || !description) {
      setFormError("Please enter the title and the description.");
      return;
    }

    console.log("TODO: call the GraphQL API and redirect");
  };

  return (
    <>
      <Container maxWidth="container.lg">
        <HStack w="fill" justifyContent="space-between" mt={8} mb={4}>
          <Heading as="h1" size="lg">back4app-graphql</Heading>
          <Link href="/">
            <Button size="sm" colorScheme="blue">
              View list
            </Button>
          </Link>
        </HStack>
        <Card>
          <CardHeader>
            <Stack direction="column">
              <Heading as="h2" size="md">Create task</Heading>
              <Text>
                Fill out the form and press &quot;Create&quot; to create a new task.
              </Text>
            </Stack>
          </CardHeader>
          <CardBody>
            <form onSubmit={handleSubmit}>
              <Stack direction="column">
                {formError && <Text color="red.500" fontWeight="bold">{formError}</Text>}
                <FormControl>
                  <FormLabel>Name</FormLabel>
                  <Input type="text" value={name} onChange={(event) => setName(event.target.value)}/>
                </FormControl>
                <FormControl>
                  <FormLabel>Description</FormLabel>
                  <Input type="text" value={description} onChange={(event) => setDescription(event.target.value)}/>
                </FormControl>
                <FormControl display="flex" alignItems="center">
                  <FormLabel mb="0">
                    Is done?
                  </FormLabel>
                  <Switch isChecked={isDone} onChange={() => setIsDone(!isDone)}/>
                </FormControl>
                <Button size="sm" colorScheme="blue" type="submit">Create task</Button>
              </Stack>
            </form>
          </CardBody>
        </Card>
      </Container>
    </>
  );
};

export default CreatePage;
  1. 今回もChakraUIコンポーネントを使用してUIを作成した。
  2. タスクを作成するためのReact制御のフォームを作成しました。
  3. 関数handleSubmit()は、APIリクエストを送信するために後で利用される。

ウェブサーバーを再起動し、http://localhost:3000。ハードコードされた2つのタスクが表示されるはずです。次に、”Create task “をクリックすると、タスク作成フォームが表示されます。

Back4app GraphQL作成タスク

GraphQLクライアント

フロントエンドからGraphQL APIに接続するには、まずGraphQL Clientをインストールする必要がある。Apolloクライアントを使用することをお勧めする。なぜなら、セットアップが簡単で、非オピニオン型であり、多くの定型文を必要としないからだ。

まず、@apollo/clientと graphqlをインストールする:

$ yarn add @apollo/client graphql

クライアントを初期化するには、Back4app API認証情報を提供する必要があります。認証情報を取得する最も簡単な方法は、GraphQL Consoleに移動し、ヘッダをメモすることです。

Back4app GraphQL認証情報

ソースコードでAPIキーを公開したくないので、プロジェクト・ルートに以下の内容の.env.localファイルを作成する:

# .env.local

NEXT_PUBLIC_PARSE_APPLICATION_ID=<YOUR_PARSE_APP_ID>
NEXT_PUBLIC_PARSE_MASTER_KEY=<YOUR_PARSE_MASTER_KEY>
NEXT_PUBLIC_PARSE_CLIENT_KEY=<YOUR_PARSE_CLIENT_KEY>

次に、pages/_app.tsxに移動し、Apolloクライアントを初期化し、次のようにApolloProviderでアプリケーションをラップします:

// pages/_app.tsx

// ...
import {ApolloClient, ApolloProvider, InMemoryCache} from "@apollo/client";

const client = new ApolloClient({
  uri: "https://parseapi.back4app.com/graphql",
  headers: {
    "X-Parse-Application-Id": process.env.NEXT_PUBLIC_PARSE_APPLICATION_ID,
    "X-Parse-Master-Key": process.env.NEXT_PUBLIC_PARSE_MASTER_KEY,
    "X-Parse-Client-Key": process.env.NEXT_PUBLIC_PARSE_CLIENT_KEY,
  },
  cache: new InMemoryCache(),
});

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <ChakraProvider theme={theme}>
      <ApolloProvider client={client}>
        <Component {...pageProps} />
      </ApolloProvider>
    </ChakraProvider>
  );
}

フロントエンドがリコンパイルされるのを待ってから、ウェブアプリにアクセスし、コンソールにエラーがないか確認してください。エラーがなければ、接続は成功しています。

GraphQLクエリと変異

最後にしなければならないのは、GraphQLクエリーとミューテーションを定義し、Reactのコードからそれらを呼び出すことだ。

IDEでGraphQLコードアシスタンスを有効にするには、Back4app GraphQL Consoleに移動し、サイドバーで “Schema “を選択し、SDLとしてダウンロードします。そして、プロジェクトルートにschema.graphqlという名前の新しいファイルを作成し、SDLの内容を貼り付けます。

まず、pages/index.tsxに移動し、インポートの後に以下のクエリーを追加する:

// pages/index.tsx

const GET_TASKS = gql`
  query GetTasks {
    tasks {
      count
      edges {
        node {
          id
          name
          description
          isDone
        }
      }
    }
  }
`;

const UPDATE_TASK = gql`
  mutation UpdateTask($id: ID!, $isDone: Boolean!) {
    updateTask(input: { id: $id, fields: { isDone: $isDone } }) {
      task {
        isDone
        updatedAt
      }
    }
  }
`;

const DELETE_TASK = gql`
  mutation DeleteTask($id: ID!) {
    deleteTask(input: { id: $id }) {
      task {
        id
      }
    }
  }
`;

これら3つのクエリーは、とてもわかりやすい。最初のクエリーはすべてのタスクのリストを返し、2番目のクエリーは特定のタスクのisDoneプロパティを更新し、3番目のクエリーは特定のタスクを削除します。

次に、ListPageのトップを次のように修正する:

// pages_index.tsx

// ...

const ListPage: NextPage = () => {

  const {loading, error, data, refetch} = useQuery(GET_TASKS);
  const [deleteTask] = useMutation(DELETE_TASK);
  const [updateTask] = useMutation(UPDATE_TASK);

const handleMarkAsDone = async (id: string, isDone: boolean) => {
    try {
      const updateTaskResponse = await updateTask({
        variables: {id: id, isDone: !isDone}
      });
      console.debug(updateTaskResponse);
      refetch();
    } catch (error) {
      console.error(error);
    }
  };

  const handleDelete = async (id: string) => {
    try {
      const deleteTaskResponse = await deleteTask({
        variables: {id: id},
      });
      console.debug(deleteTaskResponse);
      refetch();
    } catch (error) {
      console.error(error);
    }
  };

  if (error) return <p>Oops, something went wrong.</p>;
  if (loading) return <Spinner/>;

  // ...
};

export default ListPage;
  1. useQuery() を使って GET_TASKSクエリを実行し、その結果を保存しています。
  2. useMutation()を使用して、GraphQLの変異を定義した。
  3. 変異フックを利用するためにhandleMarkAsDone()handleDelete()を更新した。

続けて、pages/create.tsxを同様に修正する:

const CREATE_TASK = gql`
  mutation CreateTask($name: String!, $description: String, $isDone: Boolean!) {
    createTask(
      input: {
        fields: { name: $name, description: $description, isDone: $isDone }
      }
    ) {
      task {
        id
      }
    }
  }
`;

const CreatePage: NextPage = () => {

  // ...

  const [createTask] = useMutation(CREATE_TASK);

  const handleSubmit = (event) => {
    event.preventDefault();

    if (!name || !description) {
      setFormError("Please enter the title and the description.");
      return;
    }

    createTask({
      variables: {name: name, description: description, isDone: isDone}
    }).then(response => {
      router.push("/");
    });
  };

  // ...
};

export default CreatePage;

輸入のこともお忘れなく:

import {gql, useMutation, useQuery} from "@apollo/client";

最高だ!

開発サーバーを再起動し、ウェブアプリにアクセスしてください。タスクがデータベースからロードされているか確認し、新しいタスクを作成し、完了としてマークし、削除してみてください。

結論

結論として、GraphQLはその柔軟なクエリ機能と効率的なデータ検索のため、複雑なAPIを構築するのに適した選択肢です。従来のREST APIと比較して多くの利点がある一方で、プロジェクトを開始する際に考慮すべき欠点もあります。

この記事では、GraphQLの利点と欠点、REST APIとの比較、そしてGraphQLの主要な用語のいくつかを紹介した。これで、Back4app上で独自のシンプルなGraphQL APIを構築し、JavaScriptフロントエンドから接続できるようになるはずだ。

最終的なソースコードはGitHubのリポジトリから入手できる。

よくある質問

GraphQLとは何ですか?

GraphQLは、強力で柔軟なAPIを開発するためのクエリ言語およびサーバーサイドのランタイムです。

RESTとGraphQLの主な違いは何ですか?

RESTはWebサービスを構築するための標準的でシンプルなアプローチですが、GraphQLはより柔軟なクエリ機能を提供し、データの取得不足や取得過多を解消します。

GraphQLでよく使われる用語は何ですか?

– スキーマ は、GraphQL APIを通じて利用可能なデータの説明です。
– リゾルバ は、GraphQLクエリ内の特定のフィールドのデータを取得する関数です。
– クエリ は、GraphQL APIからデータを読み取り専用でリクエストするものです。
– ミューテーション は、GraphQL API内のデータを操作するためのリクエストです。
– サブスクリプション は、GraphQL APIからリアルタイムで更新を受け取るためのリクエストです。

GraphQL APIを構築するには?

1. Back4appで無料アカウントを作成します。
2. データベースモデルを設計します。
3. Back4app GraphQL APIコンソールを使用してクエリやミューテーションを作成します。
4. フロントエンドプロジェクトにGraphQLクライアント(ApolloやRelayなど)をインストールします。
5. クライアントを初期化し、GraphQL APIに接続します。


Leave a reply

Your email address will not be published.