QualityTrackerのAPIとその活用について

# はじめに
VALTES Advent Calendar　20日目を担当します。@kiyonori_furukawaです。
VALTES Advent Calendar初日に@kuroshiba_komomameさんが紹介されたQualityTrackerの開発を行っております。

https://qiita.com/kuroshiba_komomame/items/cc3c1a12216904a57192

QualityTrackerでは他サービスと連携して使用できるようにAPIを公開しております。
今回は、QualityTrackerで採用しているGraphQLというAPI規格についてと、
QualityTrackerのAPI利用方法についてご紹介しようと思います。

# GraphQLについて
QualityTrackerのAPIではGraphQLというAPI規格を採用しています。
QualityTrackerのAPIを紹介する前に、まずGraphQLの特長について説明します。

### 1. リクエストメソッドはPOST、エンドポイントは/graphqlのみ
GraphQLのリクエストメソッドはPOST、リクエスト先のエンドポイントは/graphqlのみです。
GraphQL以外に一般的なAPIの規格としてRESTがありますが、
RESTでは取得、追加、削除等に応じたGET、POST、DELETE等のメソッドや操作に応じたエンドポイントが設けられます。
しかし、GraphQLはメソッドPOSTのみ、エンドポイント一つとシンプルな作りになっています。
以下がQualityTrackerのAPIリクエスト先です。
* リクエストメソッド
POST
* リクエストURI
https://{サブドメイン名}.quality-tracker.com/graphql


### 2. リクエストクエリに入れられた項目のみを返す
GraphQLではリクエストのクエリに入れられた項目のみを返す仕様となっております。
必要な情報のみに絞ったデータ取得が出来るため、通信容量を抑制したデータ取得を行う事が出来ます。
以下がQualityTrackerのリクエストクエリの例です。
#### 例）テストケース取得
タグに「T-DASH」と入っているテストケースを取得します。
testItemやtagNames以外の項目も取得できますが、リクエストクエリに含めないことで項目を絞った取得を行っています。
``` getTestCases.graphql
query {
  getTestCases(
    filter:{
      tags:["T-DASH"]
    },
  ) {
    testCases{
      testItem
      tagNames
    }
  }
}
```
``` レスポンス.json
{
    "data": {
        "getTestCases": {
            "testCases": [
                {
                    "testItem": "QTのログインが成功する",
                    "tagNames": [
                        "T-DASH"
                    ],
                },
                {
                    "testItem": "QTのログインが失敗する",
                    "tagNames": [
                        "T-DASH"
                    ],
                },
                {
                    "testItem": "QTの本番環境へのログインが成功する",
                    "tagNames": [
                        "T-DASH"
                    ],
                }
            ]
        }
    }
}
```

### 3. 子や孫の情報まで一括取得できる
GraphQLでは取得対象の情報と親子関係を持った情報であれば一括で取得することが出来ます。
以下が子や孫の情報を一括取得するリクエストクエリの例です。
#### 例）プロジェクト取得
プロジェクトの情報と子のテストラン、さらに孫となるテスト結果を取得しています。

``` getProjects.graphql
query{
  getProjects(
    params:{
        archive: false
    }
  ){
    id
    name
    status
    testRuns{
      id
      name
      testResults{
        testCaseId
        testEnvironmentGroupId
        testResultStatus{
          id
          name
        }
      }
    }
  }
}
```
``` レスポンス.json
{
	"data": {
		"getProjects": {
			"projects": [
				{
					"id": 20,
					"name": "QT_T-Dashプロジェクト",
					"productId": 1,
					"status": "opening",
					"TestRuns": [
						{
							"id": 100,
							"name": "#1",
							"testResults": [
								{
									"testCaseId": 20100,
									"testEnvironmentGroupId": 1164,
									"testResultStatus": {
										"id": 3,
										"name": "Untested"
									}
								},
								{
									"testCaseId": 20101,
									"testEnvironmentGroupId": 1164,
									"testResultStatus": {
										"id": 3,
										"name": "Untested"
									}
								},
								{
									"testCaseId": 20102,
									"testEnvironmentGroupId": 1164,
									"testResultStatus": {
										"id": 3,
										"name": "Untested"
									}
								},
								{
									"testCaseId": 20103,
									"testEnvironmentGroupId": 1164,
									"testResultStatus": {
										"id": 3,
										"name": "Untested"
									}
								}
							]
						}
					]
				}
			]
		}
	}
}
```

シンプルエンドポイントやクエリに応じた柔軟な情報取得を行える点がGraphQLの大きな魅力です。


# QualityTracker APIの活用について
QualityTrackerではテストケースの取得や追加・更新、プロジェクトの取得やテスト結果の追加等をAPIで行う事が出来ます。
QualityTracker APIを活用してどのような事が出来るかをご紹介いたします。

### 1.テストケースの一括追加・更新
QualityTrackerのAPIではテストケースの追加や更新を１度に行うためのAPIが用意されています。
REST APIで作った場合、追加や更新は別々のエンドポイントになってしまうので追加・更新を１度に行う事は出来ません。
しかし、GraphQLの柔軟なリクエストを組める仕様を生かして追加・更新を1度で行うAPIを実現しました。
以下がリクエストクエリの例です。

#### テストケース追加更新API
sequentialId:10のテストケース更新と２件のテストケース追加を同時に行っています。
``` upsertTestCases.graphql
mutation{
  upsertTestCases(
    input:{
      params: [
        {
          sequentialId: 10,
          testItem: "QTのログインが成功する"
          steps: "「http://valtes-seimei.qt.com/」をブラウザで開く\n「ログイン」画面の「メールアドレス」に「user1@valtes-seimei.co.jp」を入力する\n「ログイン」画面の「パスワード」に「12345678」を入力する\n「ログイン」画面の「ログイン」をクリックする"
          expectedResult:"「ダッシュボード」画面の「すべてのプロジェクト」が表示されていること"
          testSuiteName: "QT_ローカル環境ログインテスト"
          tags:["T-DASH"]
        },
        {
          testItem: "QTのログインが失敗する"
          steps: "「http://valtes-seimei.qt.com/」をブラウザで開く\n「ログイン」画面の「ログイン」をクリックする"
          expectedResult:"「ログイン」画面の「メールアドレスまたはパスワードが空です」が表示されていること"
          testSuiteName: "QT_ローカル環境ログインテスト"
          tags:["T-DASH"]
        },
        {
          testItem: "QTの本番環境へのログインが成功する"
          steps: "「https://valtes-seimei.quality-tracker.com/」をブラウザで開く\n「本番ログイン」画面の「メールアドレス」に「xxxxxxxx@valtes.co.jp」を入力する\n「本番ログイン」画面の「パスワード」に「xxxxxxx」を入力する\n「本番ログイン」画面の「ログイン」をクリックする"
          expectedResult:"「本番ダッシュボード」画面の「すべてのプロジェクト」が表示されていること"
          testSuiteName: "QT_本番環境ログインテスト"
          tags:["T-DASH"]
        }
      ]
    }
  ){
    testCases{
      sequentialId
      testItem
      steps
      expectedResult
      testSuiteName
      tagNames
      updatedAt
    }
  }
}
```
``` レスポンス.json
{
  "data": {
    "upsertTestCases": {
      "testCases": [
        {
          "sequentialId": 10,
          "testItem": "QTのログインが成功する",
          "steps": "「http://valtes-seimei.qt.com/」をブラウザで開く
「ログイン」画面の「メールアドレス」に「user1@valtes-seimei.co.jp」を入力する
「ログイン」画面の「パスワード」に「12345678」を入力する
「ログイン」画面の「ログイン」をクリックする",
          "expectedResult": "「ダッシュボード」画面の「すべてのプロジェクト」が表示されていること",
          "testSuiteName": "QT_ローカル環境ログインテスト",
          "tags": ["T-DASH"],
          "updatedAt": "2023-01-25T10:36:00+09:00",
        },
        {
          "sequentialId": 11,
          "testItem": "QTのログインが失敗する",
          "steps": "「http://valtes-seimei.qt.com/」をブラウザで開く
「ログイン」画面の「ログイン」をクリックする",
          "expectedResult": "「ログイン」画面の「メールアドレスまたはパスワードが空です」が表示されていること",
          "testSuiteName": "QT_ローカル環境ログインテスト",
          "tags": ["T-DASH"],
          "updatedAt": "2023-01-25T10:36:00+09:00",
        },
        {
          "sequentialId": 12,
          "testItem": "QTの本番環境へのログインが成功する",
          "steps": "「https://valtes-seimei.quality-tracker.com/」をブラウザで開く
「本番ログイン」画面の「メールアドレス」に「xxxxxxxx@valtes.co.jp」を入力する
「本番ログイン」画面の「パスワード」に「xxxxxxx」を入力する
「本番ログイン」画面の「ログイン」をクリックする",
          "expectedResult": "「本番ダッシュボード」画面の「すべてのプロジェクト」が表示されていること",
          "testSuiteName": "QT_本番環境ログインテスト",
          "tags": ["T-DASH"],
          "updatedAt": "2023-01-25T10:36:00+09:00",
        }
      ]
    }
  }
}
```

### 2.テストラン取得とテスト結果追加を組み合わせてテスト結果を一括登録
テストラン取得APIとテスト結果追加APIを組み合わせることにより、
対象のテストランに対してテスト結果を一括で登録することが出来ます。
このAPIの組み合わせを利用すれば、自動テストで実行した結果をQualityTrackerの対象のテストランに自動で登録するという機能を実現することもできます。
以下がリクエストクエリの例です。

#### テストラン取得API
``` getTestRuns.graphql
query {
  getTestRuns(
    params:{
      projectId: 1
      testRunId: 1
    }
  ){
    id
    name
    projectId
    testResults{
      id
      testCase{
        sequentialId
      }
      testEnvironmentGroupId
    }
  }
}
```
``` レスポンス.json
{
	"data": {
		"getTestRuns": [
			{
				"id": 1,
				"name": "#1",
				"projectId": 1,
				"testResults": [
					{
						"id": 90370,
						"testCase"{
							"sequentialId": 1
						}
						"testEnvironmentGroupId": 1301,
					},
					{
						"id": 90370,
						"testCase"{
							"sequentialId": 2
						}
						"testEnvironmentGroupId": 1301,
					},
					{
						"id": 90370,
						"testCase"{
							"sequentialId": 3
						}
						"testEnvironmentGroupId": 1301,
					}
				]
			}
		]
	}
}
```
#### テスト結果追加API
テストラン取得APIで取得したsequentialIdとtestEnvironmentGroupIdを追加対象のテスト結果として、リクエストに入れています。
また、statusTypeには1(Passed)もしくは2(Faild)を入れています。
``` addTestResultsPassFailOnly.graphql
mutation{
  addTestResultsPassFailOnly(
    input:{
      param:{
        testRunId: 1
        testResults: [
          {
            sequentialId: 1
            testEnvironmentGroupId: 1301
            statusType: 1
          },
          {
            sequentialId: 2
            testEnvironmentGroupId: 1301
            statusType: 2
          },
          {
            sequentialId: 3
            testEnvironmentGroupId: 1301
            statusType: 1
          }
        ]
      }
    }
  ){
    testResults{
      id
      testRunId
      testCase{
        sequentialId
        testItem
      }
      testEnvironmentGroup{
        id
        productProjectTestEnvironmentSettings{
          testEnvironment{
            name
            environmentVersion
          }
        }
      }
      testResultStatus{
        name
        statusType
      }
    }
  }
}
```
``` レスポンス.json
{
	"data": {
		"addTestResultsPassFailOnly": {
			"testRuns":[
				{
					"id": 1,
					"projectId": 1,
					"testResults": [
						{
							"id": 34567,
							"testCase" {
								"sequentialId": 1,
								"testItem": "QTのログインが成功する"
							},
							"testEnvironmentGroup": {
								"id": 1301,
								"productProjectTestEnvironmentSetting": {
									"testEnvironment": {
										"name": "Google Chrome",
										"environmentVersion": "最新"
									}
								}
							}
							"testResultStatus": {
								"name": "Passed",
								"statusType": "passed"
							}
						},
						{
							"id": 34568,
							"testCase" {
								"sequentialId": 2,
								"testItem": "QTのログインが失敗する"
							},
							"testEnvironmentGroup": {
								"id": 1301,
								"productProjectTestEnvironmentSetting": {
									"testEnvironment"{
										"name": "Google Chrome",
										"environmentVersion": "最新"
									}
								}
							}
							"testResultStatus": {
								"name": "Failed",
								"statusType": "failed"
							}
						},
						{
							"id": 34569,
							"testCase" {
								"sequentialId": 3,
								"testItem": "QTの本番環境へのログインが成功する"
							},
							"testEnvironmentGroup": {
								"id": 1301,
								"productProjectTestEnvironmentSetting": {
									"testEnvironment"{
										"name": "Google Chrome",
										"environmentVersion": "最新"
									}
								}
							}
							"testResultStatus": {
								"name": "Passed",
								"statusType": "passed"
							}
						}
					]
				}
			]
		}
	}
}
```

# 最後に
今後、QualityTrackerではAPIで様々な操作が出来るように随時APIを追加していく予定です。
QualityTrackerを今後利用して頂く際は円滑な導入やテスト管理を行うために、是非APIを利用してみてください。