# Reporting API のベストプラクティス

> Tapjoy Offerwall Reporting API のエンドポイント、リクエストの構造、エラー処理について理解を深め、正確な収益化データに効果的にアクセスします。

Reporting API を使用すると、広告主とパブリッシャーは GraphQL クエリ言語を使用して、Tapjoy プラットフォームのレポートデータにアクセスし、オファーウォールコンテンツを管理できます。GraphQL の詳細については、GraphQL の公式 [ウェブサイト](https://graphql.org/) を参照してください。

API [エクスプローラー](https://api.tapjoy.com/graphql/docs/explorer) は、クエリの作成を支援します。左上隅にある本のアイコンをクリックすると、ドキュメントエクスプローラーが展開され、クエリで使用できるフィールドと指標に関する情報が表示されます。

![本アイコンをクリックすると表示される Reporting API エクスプローラーのドキュメントエクスプローラーパネル](/api/media?file=/grow/media/images/reporting_api_explorer.png)

## API エンドポイント##api-endpoint

Reporting API には 1 つのエンドポイントがあります。

```json
https://api.tapjoy.com/graphql
```

エンドポイントは、実行される操作に関係なく、同じままです。

## API との通信##communicating-with-the-api

アクセストークンを取得したら、API にリクエストできます。クエリとミューテーションのどちらを実行する場合でも、JSON エンコードされた本文が HTTP POST を介して提供され、API のリクエストを形成できます。

リクエストの例:

以下の例は、Raw HTTP、curl、および Ruby を使用して API に認証リクエストを行う方法を示しています。

1. **Raw**

   ```text
   POST /graphql
   Host: api.tapjoy.com
   Authorization: Bearer <OAuth Token>

   {
     "query": "query { user { firstName } }"
   }
   ```

2. **Curl**

   ```curl

   curl -H "Authorization:Bearer <OAuth Token>" -X POST -d "\
   {\
     \"query\": \"query { user { firstName } }\"\
   }\
   " https://api.tapjoy.com/graphql
   ```

   ```ruby title="Ruby"

   require 'json'
   require 'net/https'

   access_token = "<OAuth Token>"

   query = <<~END
   query {
     user {
       firstName
     }
   }
   END
   json = JSON.dump({query: query})

   http = Net::HTTP.new('api.tapjoy.com', 443)
   http.use_ssl = true

   request = Net::HTTP::Post.new('/graphql')
   request['Authorization'] = "Bearer #{access_token}"
   request.body = json
   response = http.request(request)

   result = JSON.parse(response.body)
   data = result['data']
   errors = result['errors']
   ```

## エラーへの対処##working-with-errors

API の使用時に発生する可能性のあるエラーには、以下のいくつかのカテゴリがあります。

* サーバー/ネットワークエラー
* 認証/承認エラー
* クエリ構文エラー
* データ検証エラー

システムを適切に統合するには、システムがこれらのカテゴリのエラーをどのように処理すべきかを検討する必要があります。

> **Note:**
>
> Reporting API はアトミックです。つまり、1 つのクエリで複数のアクションを実行する場合、構成ステップのいずれかが失敗するとクエリ全体が失敗します。

以下で説明する各カテゴリは、コンテキストに以下のクエリを使用します。

```json
query {
  user {
    firstName
    lastName
  }
}
```

### サーバー/ネットワークエラー##server-and-network-errors

たまに API で回復不能なサーバー/ネットワークエラーが発生することがあります。このような場合、発生しているシナリオに適した http 状態コードを受け取ります。例えば、API でクエリの実行を妨げる問題が発生した場合、500 の状態コードの HTTP レスポンスを受け取ります。

このシナリオに対処する最善の方法は、指数関数的バックオフによる再試行動作を採用することです。

### 認証エラーと承認エラー##authentication-and-authorization-errors

承認/承認エラーは、以下のいくつかの理由で発生することがあります。

* OAuth トークンが期限切れになった
* OAuth トークンが無効である
* 基盤となる認証システムに問題が発生している

このような状況では、以下のデータが含まれる HTTP 200 OK レスポンスを受け取ります。

認証を検証できない場合に以下の反応が返されます。

```json
{
  "errors": [
    {
      "message":"Authentication could not be verified.Please try again later.",
      "code":403
    }
  ]
}
```

* `message` - 人間が判読できるエラーの説明
* `code` - HTTP 状態コードに対応する GraphQL 状態コード

このシナリオに対処する最善の方法は、新しいアクセストークンをリクエストし、リクエストを再試行することです。

### クエリ構文エラー##query-syntax-errors

すべてのクエリとミューテーションは、構文的に正しく、説明されているデータスキーマに従っていることが事前に検証されます。指定したクエリがすべてのスキーマ検証に合格しない場合、以下のデータが含まれる HTTP 200 OK レスポンスを受け取ります。

以下の反応は、クエリがスキーマ検証に失敗した場合に返されます。これには、エラーの影響を受ける場所とフィールドが含まれます。

```json
{
  "errors": [
    {
      "message":"Field 'user' doesn't exist on type 'Query'",
      "locations": [
        {
          "line":2,
          "column":3
        }
      ],
      "fields": [
        "query",
        "user"
      ]
    }
  ]
}
```

* `message` - 人間が判読できるエラーの説明
* `locations` - 構文エラーの場所
* `fields` - 構文エラーの影響を受けるフィールド

このシナリオに対処する最善の方法は、API ドキュメントを参照し、[対話型エクスプローラー](https://api.tapjoy.com/graphql/docs/explorer) でクエリをテストすることです。

### データ検証エラー##data-validation-errors

すべての必須フィールドが入力され、適切に構築されたミューテーションを提供しても、ビジネスの検証によって失敗する可能性があります。例えば、以下のように広告主が AdSet の入札額を下限値未満に変更したとします。

以下の変換では、入札額を最小許容値未満に設定しようとします。

```json
mutation {
  updateAdSet(input: {
    id:"00000000-0000-0000-0000-000000000000",
    bidding: {amount:10000}
  }) {
    adSet {
      id
    }
  }
}
```

この場合は、HTTP 200 OK レスポンスを以下のデータとともに受け取ります。

```json
{
  "data": {
    "updateAdSet": null
  },
  "errors": [
    {
      "message":"Amount is below the minimum (20000 micros)",
      "locations": [
        {
          "line":2,
          "column":3
        }
      ],
      "path": [
        "updateAdSet",
        "input",
        "bidding",
        "amount"
      ],
      "code":422
    }
  ]
}
```

* `message` - 人間が判読できるエラーの説明
* `locations` - 検証エラーの場所
* `path` - 無効と判断されたフィールドへの完全修飾された参照
* `code` - HTTP 状態コードに対応する GraphQL 状態コード

このシナリオに対処する最善の方法は、(パス経由で) エラーメッセージを対応するフィールドとともにユーザーに表示することです。

## 制限事項##limitations

Reporting API には、過剰な API 呼び出しや濫用的な API 呼び出しを防止するための一定の保護が備わっています。統合が上限を超えている場合は、Tapjoy のアカウントマネージャーやサポートに連絡して、統合を最適化する方法や上限を増やす方法を確認してください。

以下の例は広告主のコンテキストで示されていますが、パブリッシャーの統合にも適用されます。

### データリテンション##data-retention

Reporting API は過去 2 年間のデータにアクセスできます。

### ページ処理##pagination

ページ処理タイプをクエリする場合、クライアントは以下を行う必要があります。

* `first` または `last` 引数を指定する
* 1 ページ 100 ノード以下にする

最大値を超えた場合、結果は切り捨てられ、その結果、要求された最初と最後の引数は無視されます。例を次に示します。

```graphql
{
  advertiser {
    adSets(first: 50) {
      edges {
        node {
          id
          name

          ads(first:50) {
            edges {
              node {
                id
                name
              }
            }
          }
        }
      }
    }
  }
}

```

上記のクエリでは、最大 50 の広告セットが返されます。各セットの最大広告数は 50 です。

コレクション全体をページ処理するには、`after` 引数または `before` 引数を指定して、ページの開始位置をコントロールする必要があります。例を次に示します。

```graphql
{
  advertiser {
    adSets(first:50, after:"Mg==") {
      edges {
        node {
          id
          name
        }
      }

      pageInfo {
        endCursor
        hasNextPage
      }
    }
  }
}
```

上記のクエリでは、カーソル位置 "Mg==" から最大 50 個の広告セットが返されます。その位置は、前のクエリから返された endCursor に基づいて決定されます。hasNextPage が false のとき、ページ処理は完了したと見なされます。

ページ処理の詳細については、[GraphQL のウェブサイト](https://graphql.org/learn/pagination/#pagination-and-edges) を参照してください。

### 呼び出しの複雑さ##call-complexity

スキーマ検証に合格するには、すべての Marketing API 呼び出しが 10,000 回を超えてはなりません。この場合の "呼び出し" とは、リソースのリクエストを指します。GraphQL では、複数の呼び出しを 1 つのクエリにまとめることができるため、1 つのクエリの呼び出しの合計数は、クエリが実行される前に API によって事前に計算されます。

呼び出しの数は、結果から選択されたリソース (例えば、キャンペーン、広告セット、広告、アプリ、分析情報など) の数とほぼ等しくなります。

上記の同じ例を考えてみましょう。

```graphql
{
  advertiser {
    adSets(first:50) {     # <= 50 calls
      edges {
        node {
          id
          name

          ads(first:50) {  # <= 50 calls
            edges {
              node {
                id
                name
              }
            }
          }
        }
      }
    }
  }
}
```

この例では、クライアントは一度に最大 50 個の広告セットを要求します。各広告セットにつき、クライアントはその広告セットから最大 50 個の広告を要求します。

合計呼び出し数は、以下のように計算します。

```text
50      = 50 ad sets
+
50 x 50 = 2500 ads
        = 2550 calls
```

現時点では、1 時間あたりの呼び出し数にレート制限はありません。ただし、これは今後変更される可能性があります。

### 分析情報の複雑さ##insights-complexity

レポートの分析情報に対してクエリを実行すると、どのようなレベルでも、上記の基本計算には反映されない複雑さのコストが追加で発生します。クエリが実行される日ごとに、さらに 1 回の呼び出しが計算に追加されます。

例を考えてみましょう。

```graphql
{
  advertiser {
    # 50 calls
    adSets(first:50) {
      edges {
        node {
          id
          name

          # 7 calls
          insights(timeRange: {from:"2024-03-01T00:00:00Z", until:"2024-03-08T00:00:00Z"}) {
            timestamps
            reports {
              country
              impressions
              conversions
              spend
            }
          }
        }
      }
    }
  }
}
```

この例では、クライアントは一度に最大 50 個の広告セットを要求します。各広告セットにつき、クライアントは 3 つの指標と 1 セグメントにわたる 7 日間分のレポートデータを要求します。

合計呼び出し数は、以下のように計算します。

```text
50      = 50 ad sets
+
50 x 7  = 350 insights
        = 400 calls
```
