見出し画像

開発日記(2024/05/16)App Store Conect APIのsalesReportsが取得できない

<前回までのおさらい>GWを返上してApp Store Conect APIの仕様を理解したにも関わらず、いざリクエストを送ると500エラーが返ってきてしまうという悲しい事態に。。。

1日経っても状況変わらずなので、問い合わせてみる。「開発と技術」から「APIとキー」を選択。

まで開いて、あれ、、ひょっとして呼び出し方に問題があったのでは・・・と思い至る。。もう一回公式ドキュメントに戻ると・・・

ほら、パラメーター必要って書いてあるじゃん。

ぎゃー、、まじか。助けてGPTえもん。で、生成いただいたコードが下記。

const jwt = require('jsonwebtoken');
const fs = require('fs');
const axios = require('axios');

// 秘密鍵の読み込み
const privateKey = fs.readFileSync('ここに秘密鍵のファイル.p8', 'utf8');

// ヘッダ情報
const header = {
  alg: 'ES256',
  kid: 'ここはkey ID',
  typ: 'JWT'
};

// ペイロード情報
const payload = {
  iss: 'ここはIssuer ID',
  iat: Math.floor(Date.now() / 1000),
  exp: Math.floor(Date.now() / 1000 + 20 * 60),
  aud: 'appstoreconnect-v1'
};

// JWTトークンの生成
const token = jwt.sign(payload, privateKey, { algorithm: 'ES256', header: header });

// パラメータ
const params = {
  'filter[frequency]': 'DAILY',
  'filter[reportDate]': '2023-10-22',
  'filter[reportSubType]': 'SUMMARY',
  'filter[reportType]': 'SALES',
  'filter[vendorNumber]': 'ここはベンダー番号'
};

// アクセス先のエンドポイント
const api_url = '<https://api.appstoreconnect.apple.com/v1/salesReports>';

// API リクエストの送信
axios.get(api_url, {
  headers: {
    Authorization: `Bearer ${token}`,
    Accept: '*/*'
  },
  params: params
})
.then(response => {
  console.log(response.data);
})
.catch(error => {
  console.error(error);
});

ぐあ・・・普通に返ってくるじゃん。。ぼくが悪かったです。すみません。。。

しかし、文字化けしとるな。。

そういえば返却値はgzipみたいな話がありましたね・・・

便利な世の中になったなあ・・・

何度か調整して下記に落ちつく。

const jwt = require('jsonwebtoken');
const fs = require('fs');
const axios = require('axios');
const zlib = require('zlib');

// 秘密鍵の読み込み
const privateKey = fs.readFileSync('ここに秘密鍵のファイル.p8', 'utf8');

// ヘッダ情報
const header = {
  alg: 'ES256',
  kid: 'ここはkey ID',
  typ: 'JWT'
};

// ペイロード情報
const payload = {
  iss: 'ここはIssuer ID',
  iat: Math.floor(Date.now() / 1000),
  exp: Math.floor(Date.now() / 1000 + 20 * 60),
  aud: 'appstoreconnect-v1'
};

// JWTトークンの生成
const token = jwt.sign(payload, privateKey, { algorithm: 'ES256', header: header });

// パラメータ
const params = {
  'filter[frequency]': 'DAILY',
  'filter[reportDate]': '2023-10-22',
  'filter[reportSubType]': 'SUMMARY',
  'filter[reportType]': 'SALES',
  'filter[vendorNumber]': 'ここはベンダー番号'
};

// アクセス先のエンドポイント
const api_url = '<https://api.appstoreconnect.apple.com/v1/salesReports>';

// TSVをJSONに変換する関数
function tsvToJson(tsv) {
  const lines = tsv.split('\\n');
  const headers = lines[0].split('\\t');
  return lines.slice(1).map(line => {
    const data = line.split('\\t');
    return headers.reduce((obj, header, index) => {
      obj[header] = data[index];
      return obj;
    }, {});
  });
}

// API リクエストの送信
axios.get(api_url, {
  headers: {
    Authorization: `Bearer ${token}`,
    Accept: '*/*',
    'Accept-Encoding': 'gzip'  // gzipでの圧縮を受け入れる
  },
  params: params,
  responseType: 'arraybuffer'  // バイナリデータとしてレスポンスを受け取る
})
.then(response => {
  // gzip解凍
  zlib.gunzip(response.data, (err, buffer) => {
    if (err) {
      console.error('解凍エラー:', err);
      return;
    }
    const tsvData = buffer.toString();
    const jsonData = tsvToJson(tsvData);

    // JSONデータをコンソールに出力
    console.log(JSON.stringify(jsonData, null, 2));
  });
})
.catch(error => {
  console.error('リクエストエラー:', error.response ? error.response.data : error.message);
});

結果!わ〜返ってきた〜!

”Units”に記載の値がインストール数ですね!

パラメーターに指定の日付を動的に変えねばですね。ということで、前日の値を設定して欲しいので、

ありがたやありがたや
dconst jwt = require('jsonwebtoken');
const fs = require('fs');
const axios = require('axios');
const zlib = require('zlib');

// 秘密鍵の読み込み
const privateKey = fs.readFileSync('ここに秘密鍵のファイル.p8', 'utf8');

// ヘッダ情報
const header = {
  alg: 'ES256',
  kid: 'ここはkey ID',
  typ: 'JWT'
};

// ペイロード情報
const payload = {
  iss: 'ここはIssuer ID',
  iat: Math.floor(Date.now() / 1000),
  exp: Math.floor(Date.now() / 1000 + 20 * 60),
  aud: 'appstoreconnect-v1'
};

// JWTトークンの生成
const token = jwt.sign(payload, privateKey, { algorithm: 'ES256', header: header });

// 前日の日付を取得する関数
function getYesterdayDate() {
  const date = new Date();
  date.setDate(date.getDate() - 1);
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, '0'); // 月は0から始まるため、+1する
  const day = String(date.getDate()).padStart(2, '0');
  return `${year}-${month}-${day}`;
}

// パラメータ
const params = {
  'filter[frequency]': 'DAILY',
  'filter[reportDate]': getYesterdayDate(),
  'filter[reportSubType]': 'SUMMARY',
  'filter[reportType]': 'SALES',
  'filter[vendorNumber]': 'ここはベンダー番号'
};

// アクセス先のエンドポイント
const api_url = '<https://api.appstoreconnect.apple.com/v1/salesReports>';

// TSVをJSONに変換する関数
function tsvToJson(tsv) {
  const lines = tsv.split('\\n');
  const headers = lines[0].split('\\t');
  return lines.slice(1).map(line => {
    const data = line.split('\\t');
    return headers.reduce((obj, header, index) => {
      obj[header] = data[index];
      return obj;
    }, {});
  });
}

// API リクエストの送信
axios.get(api_url, {
  headers: {
    Authorization: `Bearer ${token}`,
    Accept: '*/*',
    'Accept-Encoding': 'gzip'  // gzipでの圧縮を受け入れる
  },
  params: params,
  responseType: 'arraybuffer'  // バイナリデータとしてレスポンスを受け取る
})
.then(response => {
  // gzip解凍
  zlib.gunzip(response.data, (err, buffer) => {
    if (err) {
      console.error('解凍エラー:', err);
      return;
    }
    const tsvData = buffer.toString();
    const jsonData = tsvToJson(tsvData);

    // JSONデータをコンソールに出力
    console.log(JSON.stringify(jsonData, null, 2));
  });
})
.catch(error => {
  if (error.response && error.response.data) {
    const errorMessage = error.response.data.toString('utf8');
    console.error('リクエストエラー:', errorMessage);
  } else {
    console.error('リクエストエラー:', error.message);
  }
});

成功!ダウンロード数がゼロの日は404が返るそうなので、挙動としては正常ですね。

ではこれをGCFにアップロードしていただいて、、、あ、でもそれだとテストができないので、、、一旦は日付は固定値でテストしてみる感じかな???

次回で完成させたいなあ・・・

ご覧いただきありがとうございます。とても嬉しいです。