API Connect for GraphQL で試す新API体験 【2】ツールの操作とオーバーフェッチ対応

## はじめに
「GraphQL」という技術を今から把握したいという方向けに、IBMが提供するAPI Connect for GraphQLというサービスを使ったデータアクセス体験を解説します。

記事は次の3つに分かれます。当記事では、裏側に控えるデータソースとGraphQLの接続、および不要な結果を取得しないオーバーフェッチを試します。
1. [GraphQLの解説と準備](https://qiita.com/mi-ta/items/6d353872f48ade989a24)
2. オーバーフェッチ対応（当記事）
3. [アンダーフェッチ対応](https://qiita.com/mi-ta/items/bbfd168a299ebbf28714)

製品名が長いため、以下「**4GraphQL**」と記載します。この記事では、画面のガイドに沿ってGraphQLサーバーを構築する手順で確認していきます。慣れればガイドどおりの順序でなくても構いません。

## 4GraphQL の管理構造
4GraphQLの管理構造のポイントは次の2つです。
* 動作させるための定義は、定義ファイルとして4GraphQLの外（任意の管理サーバー）で管理される
* 定義ファイルと4GraphQLの同期を取ることで、必要な処理を行なわせる

<img width="600" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536604/94948b01-fa6f-95ce-5dbe-5e65aa280461.png">

設定が定義ファイルとして外部に置かれる構成のため、バージョン管理などは行ないやすいと考えます。

基本的な操作のステップは、次の流れになります。
* 管理サーバーにCLIをインストールする（初回のみ）
* 管理サーバーから4GraphQLにログインする
* CLIで、4GraphQLから対象データソースへの接続設定を行なう
* 設定が完了したら、4GraphQLと定義ファイルの同期開始をCLIで指定する

## 実現すること
RESTAPIを提供するサーバーと4GraphQLを接続し、GraphQLのリクエストを受付できるようにします。

## 準備
### インターネットからアクセスできるVMを準備する
この記事では、管理サーバー兼RESTAPIのデータソースをインターネット上に作成します。そのためパブリッククラウド上にVMを立てて、そこにセットアップを行ないます。VMのリソースは低めで問題ないでしょう。この記事ではCentOS Stream 9を使用しています。

### JsonServerのセットアップ
今回は動的に動作するRESTAPIサーバーの代わりに、モックサーバーとして使われることの多い [json-server](https://github.com/typicode/json-server) を使用します。
インストールのコマンドはおおよそ次のとおりです。

```
sudo dnf install npm
sudo npm install -g json-server
mkdir json
cd json
vi country.json
json-server --watch country.json -p 3000
```

viで編集する、モック出力用のcountry.jsonの内容は次のとおりです。
```
{
  "countryname": [
    {"id": "Japan", "Code": "JPN"},
    {"id": "Italy", "Code": "ITA"},
    {"id": "Greece", "Code": "GRC"},
    {"id": "Ireland", "Code": "IRL"},
    {"id": "New Zealand", "Code": "NZL"},
    {"id": "Spain", "Code": "ESP"},
    {"id": "Portugal", "Code": "PRT"},
    {"id": "Israel", "Code": "ISR"},
    {"id": "Norway", "Code": "NOR"},
    {"id": "Switzerland", "Code": "CHE"}
  ]
}
```
ブラウザから次のURLを呼び出して結果が返ればOKです。接続できない場合は、ファイアウォールの設定でポート3000が使えるか確認してください。
http://YourIPAddress:3000/countryname

## 4GraphQLの設定
大きな流れは
* 必要情報を画面から入力する
* 管理サーバーで指定されたコマンドを実行する

の2ステップで簡単です。

### 接続用の情報入力
4GraphQL のホーム画面下部にある「Getting started」を選択します。
<img width="600" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536604/a43405ab-c993-dd6b-6245-3bcf33efcba1.png">

接続するバックエンドの種類を選択します。様々な接続の選択肢がありますが、ここでは「Convert REST to GraphQL」を選択します。
<img width="600" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536604/41819774-dec3-a7d7-7c60-6ce96cf589a3.png">

項番の1に、実際にRESTAPIを提供するサイトのURLを入力します。
<img width="600" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536604/96606e8f-96c5-53c4-26d3-7d1a6fa200c5.png">

### 管理サーバーの利用準備
画面上に管理サーバー向けのCLIインストールとログインのコマンドが表示されます。これをコピーしてサーバー上で実行します（npmは必要に応じてsudoで）。
ログインコマンドではadminKeyを聞かれますが、画面からキーをコピーできます（項番の3）。
<img width="600" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536604/cd9085e3-9321-c503-b131-fcb1504349f7.png">
```
npm i -g stepzen
stepzen login us-east-a.ibm.stepzen.net --account XXXXXXXXXXX
```

### 管理サーバーの利用準備
ログインコマンドが成功したら、次のページに遷移して、API公開のためのコマンドを実行していきます。
<img width="600" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536604/632b233d-60f5-f3f4-0aa3-41050dd15ea3.png">
**項番1**では、4GraphQLが外向きに公開するURLを命名します。今回デフォルトで進めます。
**項番2**のコマンドを管理サーバーで実行すると、実行したディレクトリに管理ファイルが作成されます。
```
mkdir graphql
cd graphql
stepzen init --endpoint=api/getting-started
```

同階層に stepzen.config.json が作成されます。
初期状態での内容は次のとおりですが、このファイルを中心に定義情報が積み上げられます。
```stepzen.config.json
{
  "endpoint": "api/getting-started"
}
```
**項番3**では、RESTAPIを提供するサイトを外部に公開するAPI定義を追加します。前画面で登録した内容を元にコマンドが生成されているため、これをコピーして実行します。
処理が正常終了すると、同階層の定義情報が次の3件になります。
* stepzen.config.json
* index.graphql
* rootQuery ディレクトリ

index.graphqlには、スキーマに関する情報が記録されています。実際の定義はrootQueryディレクトリ内のindex.graphqlにあります。
```
schema @sdl(files: ["rootQuery/index.graphql"]) {
  query: Query
}
```
rootQueryディレクトリ内のindex.graphqlでは、RESTAPIの定義情報として、次のような内容が出力されています。
対象のAPIはid、codeという2項目を持っており、プロダクトがこれを識別して自動でRootEntryというデータ型を生成しています。
```rootQuery/index.graphql
type RootEntry {
  Code: String
  id: String
}

type Query {
  rootQuery: [RootEntry]
    @rest(endpoint: "http://YourIPAddress:3000/countryname")
}
```
**項番4**のstartコマンドを実行します。
<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536604/65949479-db38-b5a2-f1d1-d63b069fac9f.png">
このコマンドは
* 定義ファイルをGraphQLサーバと同期する
* 定義ファイルの更新を検知してGraphQLサーバに通知する

という役割のため、startコマンドのプロセスが停止してもGraphQLサーバーは同期済の定義をもとにサービス提供を続けます。

## 4GraphQLでクエリーを試す
4GraphQLはサイドバーにメニューがあり、上から順に次の機能があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536604/6edd4616-547d-23f5-d573-c2e9238d4bef.png)
* Home
* Endpoints
* Explorer
* Analytics

ここではExplorerを使用して、APIアクセスのクエリーを作成していきます。Explorerは、APIのクエリー生成や動作確認を行なうためのツールです。

<img width="600" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536604/b04b7a11-a908-b06b-a998-b142b615db84.png">

初期状態で「Builder」が選択されますが、ここでは左側のペインから順に

* クエリーで抽出する項目を選択する
* クライアント側から発行するクエリーを表示・修正するエディタ
* エディタの実行結果を表示する

という機能を提供します。この機能で動作検証することにより、クライアント側で使いたい機能が提供できているかを確認できます。

### オーバーフェッチ対応
今回のAPIでは、モックサーバーから提供している項目はidとCodeの2つで、これをそのまま外部に公開しています。
クライアント側で「Codeは不要でidだけ取得したい」という場合に、どのようなクエリーを記述する必要があり、期待通りの結果が返るのかを確認できます。
次の画面ショットは左ペインで取得する項目を指定し、生成されたクエリーが表示されている中央ペインの実行ボタンを押して、結果を表示させた状態を示しています。
<img width="600" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536604/7344a07a-3252-75f6-ab03-1703432c7b8a.png">
期待どおりにidだけが結果に含まれていることが確認できます。

確認できた後はクライアント側で実装を残すのみとなります。画面上部の「Export」を押すと、クライアント側からの呼び出しに必要なコマンドが表示されます。
<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536604/f3d83d05-4894-9314-d9b0-0c153378f9f4.png">
この例ではCurlコマンドを表示していますが、他にもJavaScript、Python、ReactAppoloを選択できます。

### 4GraphQLで提供項目を絞る
上の例では「クライアント側が取得項目を絞る」ことを行ないました。
それ以外に「業務上、提供元APIの項目を全て公開するのは望ましくない」という状況も出てくることがあります。その場合は「サーバー側で取得できる項目を予め絞る（元から選択させないようにする）」という対処を行なう必要があります。

この場合、定義ファイルでレイアウトを変更することで特定の項目を非公開にすることができます。
先に確認した rootQuery/index.graphqlのデータ型からidを削除してstartコマンドで同期します。
```rootQuery/index.graphql
type RootEntry {
  Code: String
}

type Query {
  rootQuery: [RootEntry]
    @rest(endpoint: "http://YourIPAddress:3000/countryname")
}
```
この対応を行なう前後のExplorerの画面を確認します。
**修正前**
<img width="600" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536604/a8a00205-5383-0956-bbfb-012d3662d84a.png">
Builderの選択肢にid、Codeとも表示されており、実行結果も指定どおりに取得できています。

**修正後**
<img width="600" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536604/03638846-e5b2-2537-cfc1-aaf95cd39d01.png">
Builderからidの選択肢が外れています。中央ペインではidの指定が無効であるため、警告の下線が表示されています。
強行して実行をかけたところ、右ペインのようなエラーを返すようになりました。

このように提供元APIの項目を絞ることも4GraphQLで実現できます。
## この記事のまとめ
提供元のAPIとの接続、オーバーフェッチ対応の実現を確認しました。
4GraphQLでは「GUIが提供されていること」「4GraphQLがAPIを理解して多くの準備が自動的に行われていること」から**スキル的、工数的な観点でストレスなくGraphQLを使いはじめられる**という点に特徴があります。
これからのGraphQL利用のスタート地点としていただけると幸いです。