API ConnectでGraphQLプロキシーAPIを試してみた

# はじめに

IBM API Connect v10では、GraphQLサーバーへのリクエストをプロキシーするAPIを提供します。

この記事では、API Connectを使用して、GraphQLプロキシーAPIを作成し、テスト実行するまでの手順を紹介します。

バックエンドのGraphQLサーバーは、[「StepZenの無償版でGraphQLを試してみた」](https://qiita.com/jiszk/items/5f843ce560c8d76d9bea)で作成したサンプルを使用します。

API ConnectはAPI Connect AWS SaaS試用版を使用しました。API Connect AWS SaaS試用版の基本的な利用方法については、 [IBM API Connect as a Service on AWS 試用版を使ってみる](https://qiita.com/myamane/items/39fe5940533fdbe76547) を参照してください。


# APIの作成

1. API Connectにログインし、`「開発」`画面で新規APIを作成します。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468543/e8f71b34-92c0-d8d0-3e75-b2594027476a.png)

1. `「APIタイプの選択」`画面にて、`「既存の GraphQL サービスから (GraphQL プロキシー)」`を選択します。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468543/e6f8beac-6d88-82c9-db68-787a3aeb54d3.png)

1. GraphQLプロキシーAPIの基本情報とGraphQLサービスへ接続するための情報を設定します。
    - `情報`：タイトルや基本パスなど任意の値を指定
    - `GraphQLサービス`：プロキシーするバックエンドの情報を入力 （ここでは、StepZenのGraphQLエンドポイントの情報を入力）
   :::note warn
   今回使用するStepZenのGraphQLエンドポイントはAPI Keyで保護されているため、Authorizationヘッダーを追加してAPI Keyを指定する必要があります。
   :::
    ![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468543/4422cb5d-162b-7ab1-48ec-af1cdbd5badc.png)
    `「次へ」`をクリックし、正常にGraphQLエンドポイントに接続できると次の画面に遷移します。
   
   :::note warn
   GraphQLサービスに接続できない場合、以下のエラーが表示されます。
![3'.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468543/460318d5-8e52-8b26-5594-583f0dec3a91.png)
   :::

1. スキーマとパスを編集します。
スキーマはGraphQLエンドポイントから情報を取得します。
スキーマを置き換えたい場合は「置換」ボタンをクリックして任意のスキーマ定義ファイルをアップロードできます。
`「パス」`欄では公開するAPIのパスを選択できます。
    - `/graphql`：実際にバックエンドに接続して情報を取得するパスのため必須です。
    - `/graphql/cost`：情報取得に必要なコストを照会するためのパスです。
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468543/4dbdcd8c-1382-b225-813d-d71998bf7191.png)
    ここではデフォルトのまま`「次へ」`をクリックします。

1. `セキュア`と`APIのアクティブ化`はデフォルトのまま`「次へ」`をクリックします。
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468543/3962e8d5-2fca-ba27-a157-73aef39cdb9a.png)

1. API定義が作成されました。
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468543/05836912-4967-89de-8c64-025654c860f4.png)
`「APIの編集」`をクリックして次の手順に進みます。

# APIの編集

1. GraphQLサーバー接続時のAPI認証のための追加設定
今回使用するバックエンドのStepZen GraphQLは、APIリクエスト時にAuthorizationヘッダーでAPI Keyの指定が必要です。そのため、invokeポリシーの直前でAuthorizationヘッダーをセットします。
    まず、`ゲートウェイ`タブにて、`graphql-invoke`の直前に`変数の設定(set-variable)`ポリシーを配置し、`Add action`ボタンをクリックして以下のように指定します。
    |項目|設定値|
    |:---|:---|
    |Action|Set                          |
    |Set   |message.headers.authorization|
    |Type  |string                       |
    |Value |_Admin Key_ (apikey travilah::stepzen.io+1000::4ac3b69d000bae20...)                  |

    ![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468543/efbc84a9-9305-d062-a25f-fc61d2d8bb05.png)
    次に、AuthorizationヘッダーをGraphQLサーバーへ送信するための許可設定を追加します。自動生成されるinvokeポリシーのヘッダー制御はallow-list形式となっており、Authorizationヘッダーは許可されていないためGraphQLサーバーへ送信されません。

    `graphql-invoke`を編集し、`ヘッダー制御機構`の許可リストに`Authorization`を追加します。
![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468543/a95ebc5a-eefc-a9f0-315b-770c15bf1431.png)

1. invokeポリシーの`圧縮(compression)`オプションの無効化
自動生成されたinvokeポリシーのデフォルトでは、`圧縮`オプションが有効になっています。しかし、express-graphqlベースのGraphQLバックエンドでは圧縮を正しくハンドリングできず、OperationErrorやSyntaxErrorが発生するようです。
https://community.ibm.com/community/user/integration/discussion/grapql-operationerror

    今回使用したStepZenのGraphQLにおいても、圧縮が有効の場合はエラーが発生したため無効化します。
    `graphql-invoke`を編集し、`圧縮`オプションのチェックボックスを外します。
![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468543/36f9c39f-d1bb-7062-6b8d-ba7cc1c99e4d.png)


APIの編集が完了したら`「保存」`ボタンをクリックして設定を保存します。


# APIのテスト

API定義右上の`「オフライン」`トグルをクリックして`オンライン`にし、Sandboxカタログに公開します。
![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468543/3710e77a-2edb-2800-ce89-be98d4f2354f.png)
ここでは、API Manager UIからテスト実行する方法とcurlでAPI呼び出しする方法の2通り紹介します。

## API Manager UI

API Manager UIではGraphiQLエディターが使用可能です。
[GraphiQL](https://github.com/graphql/graphiql)はGraphQLのGUIクライアントです。

ここでは、[「StepZenの無償版でGraphQLを試してみた」](https://qiita.com/jiszk/items/5f843ce560c8d76d9bea)で実行した、**1ドルを円換算した結果を取得するクエリ**を使用して動作確認します。

API定義の`テスト`タブを開き、`要求`セクションでAPIエンドポイントを選択します。
（ここでは、```POST https://api.us-east-a.apiconnect.ibmappdomain.cloud/apiconnect-6/sandbox/test/graphql```を選択します。）
`GraphiQL`タブの左ペインに以下のとおりクエリを入力します。
```terminal
{
  frankfurter_convertedAmount(amount: 1, from: "USD", to: "JPY")
}
```
`送信`ボタン(または、エディター内の実行(Execute Query)アイコン)をクリックすると、APIが実行され、中央のペインに取得結果のデータが表示されます。
![11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468543/5bba50f0-d673-c554-5842-99691ccc40d6.png)

## curl
graphql形式とjson形式の2パターンで実行してみます。

### graphql形式

```sh
~ % curl -i -X POST 'https://api.us-east-a.apiconnect.ibmappdomain.cloud/apiconnect-6/sandbox/test/graphql' \
 -H 'x-ibm-client-id: ab4f4e5340560fa7813036cd33317f9a' \
 -H 'Content-Type: application/graphql' \
 --data '{frankfurter_convertedAmount(amount: 1, from: "USD", to: "JPY")}'
HTTP/2 200
date: Wed, 10 May 2023 05:07:21 GMT
content-type: application/json
stepzen-trace: 18e728831428800f11e25910319a4357
strict-transport-security: max-age=63072000; includeSubDomains; preload
vary: Origin
x-content-type-options: nosniff
via: 1.1 google
x-global-transaction-id: a9ee9687645b2688003d4f20
x-envoy-upstream-service-time: 550
cf-cache-status: DYNAMIC
server: cloudflare
cf-ray: 7c4fa8735a30af64-NRT

{"data":{"frankfurter_convertedAmount":135.02}}%
```

### json形式

```sh
~ % curl -i -X POST 'https://api.us-east-a.apiconnect.ibmappdomain.cloud/apiconnect-6/sandbox/test/graphql' \
 -H 'x-ibm-client-id: ab4f4e5340560fa7813036cd33317f9a' \
 -H 'Content-Type: application/json' \
 --data '{"query": "{frankfurter_convertedAmount(amount: 1, from: \"USD\", to: \"JPY\")}"}'
HTTP/2 200
date: Wed, 10 May 2023 05:07:44 GMT
content-type: application/json
stepzen-trace: 63822f6c278bbec928ecd2b4ec8f1408
strict-transport-security: max-age=63072000; includeSubDomains; preload
vary: Origin
x-content-type-options: nosniff
via: 1.1 google
x-global-transaction-id: 4c75ec11645b269f002adbe3
x-envoy-upstream-service-time: 613
cf-cache-status: DYNAMIC
server: cloudflare
cf-ray: 7c4fa900a966f629-NRT

{"data":{"frankfurter_convertedAmount":135.02}}%
```

以上、API ConnectでGraphQLサービスからGraphQLプロキシーAPIの作成から実行までを紹介しました。