Vue.js初心者がWP REST APIとGA Reporting APIを使ってスワブロランキングアプリを作ったよ

2020.04.01

vue.js初心者がWP Rest APIとGoogle Analytics APIを使ってスワブロランキングアプリを作ったよ

 

ども、むったんです。

 

コロナ騒ぎで、ライブ&イベントが軒並み中止になってとても辛い。
えぇ、分かってます。
ウイルスを蔓延させないためって分かってます。
分かってる…けどさぁーーー!推しに会いたいよーーー😭

 

 

ちなみに3月に開催予定だったライヴは中止となり、払い戻しが始まりました😭
ライブが開催できていれば、リアル推し×画面の中にいた2D推しが3Dになってステージで歌って、踊っていたと思うと…是非もう一度企画していただきたいと思う所存!
むったんが行きたかったライブはこちら

 

 

 

そして、そんな悶々とした気持ちをぶつけながら作ったのが、今回のアプリですww

 

 

スワブロランキングアプリを作った

作り始めた経緯

みなさんが見てくれているこのスワローブログ(略してスワブロ)ですが、運用が始まったのは2018年10月。
そこから月ごと&四半期ごとに、中村さんがGoogleアナリティクスからフィルターかけたりしてランキングを発表してくれていました。

 

正直この作業簡略化できそうだし、アプリにできたら中村さんの仕事の負担ちょっとは減るよなー…と思っていました。
なので、リーダー千に「中村さんの仕事の負担を減らすために、WPとアナリティクスからデータ引っ張ってきてスワブロランキングアプリ作ってええ?( ´ ▽ ` )ノ」とノリで言ったらOKをもらいました!
ということで、ざっくり書いていくよ😆

 

環境

  • WordPress 5.3.2
  • GoogleアナリティクスReporting API v4
  • Vue.js 2.6.10
  • vuex 3.1.0
  • vuetify 2.1.0

 

取得したいもの

GoogleアナリティクスReporting API v4

  • URL
  • PV数

 

WP REST API

  • URL
  • 投稿日
  • ブログタイトル
  • 投稿者

 

投稿者情報が不要であれば、GoogleアナリティクスReporting APIのみで行けたのですが…そりゃそうね、複数人で運用しているブログだもの。
投稿者は知りたいよね。

 

 

インストールしたもの

  • vuetify

詳しい導入方法は以前むつたくが紹介しているので、そちらをご覧ください。
やっぱりフレームワーク使うとラクだわ(諦めれば、cssとの戦いも放棄できると最近踏ん切りがついたw

Vue-CLI3から始めるUIフレームワーク 〜Vuetify〜

 

  • moment.js

インストール方法は以下の記事が分かりやすいです。

Vue.jsで日付処理ライブラリMoment.jsを使う|WEB PIXEL

 

  • vue-monthly-picker

年月だけ指定したかったので、以下のものを使用させていただきました🙏

vue-monthly-picker

 

  • vue-google-api

Google ApiとGoogle認証を使用して、クライアント側の操作を行うのに必要なもの。

vue-google-api

 

ざっくり流れはこんな感じ

スワブロランキング流れ

 

WP REST APIは投稿順で情報をくれるっぽい。
GA Reporting APIは好きなようにソートできるっぽいので、PV昇順に指定。

 

for文で回して、GA Reporting APIから来た内容を基準にWP REST APIの情報もまとめて、ランキングを表示しました。

 

準備(WordPress)

WordPress4.7以上であれば、プラグインなどを使用せずに下記URLから記事情報等がjson形式で取得できます。

1
 http://[ドメイン]/wp-json/wp/v2/[slug]

 

ちなみに、今回はスワブロの情報を取得したいので、こんな感じになります。

1
 https://swallow-incubate.com/wp-json/wp/v2/blog

 

取得件数の初期値は10件です。

 

 

準備(Google API)

設定が面倒だったのはこっちだった…orz
そして未だちゃんと理解してないけど、動いてるから大丈夫なのかな😅

 

ざっくり説明すると、こんな感じ。

  1. Google API ConsoleからGoogle  Analytics Reporting APIを選択
  2. プロジェクトを作成
  3. 認証情報を作成
  4. Google Analyticsにサービスアカウントを追加
  5. APIキーを発行
  6. OAuth2.0クライアントIDを発行(むったんはhttp://localhost:8080を許可、状況に応じて変更してください)

 

詳しいやり方はSAKI Web Design様のブログに書いてありますので、参考にしてみてください🙏

Google Analytics Reporting API V4 を使う①|SAKI Web Design

コード

※コードが長くなるので、CSSは書きません。

src/main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store/index'
import vuetify from './plugins/vuetify'
import VueGoogleApi from 'vue-google-api'

const config = {
  clientId: '[clientId]',
  scope: 'https://www.googleapis.com/auth/analytics',
  apiKey: '[apiKey]',
  discoveryDocs: ['https://analyticsreporting.googleapis.com/$discovery/rest?version=v4']
}

Vue.config.productionTip = false

Vue.use(VueGoogleApi, config)

new Vue({
  router,
  store,
  vuetify,
  render: h => h(App)
}).$mount('#app')

 

src/App.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<template>
  <v-app>
    <BaseLine />
    <v-content>
      <router-view />
    </v-content>
  </v-app>
</template>
<script>
import BaseLine from '@/components/BaseLine.vue'

export default {
  name: 'App',

  components: {
    BaseLine
  },

  data: () => ({
    //
  }),
};
</script>

 

src/components/BaseLine.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<template>
 
<div id="baseLine">
    <v-navigation-drawer
      v-model="drawer"
      app
    >
     
<div class="navi-box">
        <v-list mandatory>
          <v-list-item-group v-model="navi">
            <v-list-item
              v-for="(item, i) in items"
              :key="i"
              :to="item.link"
              class="d-flex"
            >
              <v-list-item-icon>
                <v-icon v-text="item.icon" color="white"></v-icon>
              </v-list-item-icon>
              <v-list-item-content>
                <v-list-item-title v-text="item.text" class="font-weight-bold"></v-list-item-title>
              </v-list-item-content>
            </v-list-item>
          </v-list-item-group>
        </v-list>
      </div>

    </v-navigation-drawer>

    <v-app-bar
      app
      color="white"
      dark
    >
      <v-app-bar-nav-icon @click.stop="drawer = !drawer" />
      <v-toolbar-title class="title font-weight-bold">Swallow Blog Ranking</v-toolbar-title>
    </v-app-bar>
  </div>
</template>
<script>
  export default {
    name: 'BaseLine',
    props: {
      source: String,
    },
    data: () => ({
      drawer: null,
      navi: null,
      item: 1,
      items: [
        { text: '1ヶ月ランキング', icon: 'mdi-calendar', link: '/' },
        { text: '3ヶ月ランキング', icon: 'mdi-calendar-multiple', link: '/three-months' }
      ]
    }),
  }
</script>

 

src/views/Home.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
<template>
  <div
    id="home"
    class="pa-5"
  >
    <v-row>
      <v-col cols="4">
        <v-card
          class="px-2 py-1"
          flat
        >
          <v-row
            class="align-center calendar"
          >
            <v-col
              cols="1"
            >
              <v-icon>mdi-calendar-blank</v-icon>
            </v-col>
            <v-col
              cols="11"
            >
              <vue-monthly-picker
                v-model="selectedMonth"
                :min="min"
                :max="currentMonth"
                :selectedBackgroundColor="bgColor"
                :clearOption=false
                dateFormat="YYYY-MM"
              ></vue-monthly-picker>
            </v-col>
          </v-row>
        </v-card>
      </v-col>
    </v-row>
    <template v-if="displayUrl.length != 0">
      <v-row
        class="card-area"
      >
        <v-col
          cols="4"
          v-for="(items, index) in limitCount"
          :key="index"
          class="topCard d-flex"
        >
          <v-card
            flat
          >      
<p class="pv">{{displayUrl[index].pv}} <span class="pv-text">pv</span></p>
<p class="date">{{displayUrl[index].date}}</p>
<p class="title">{{displayUrl[index].title}}</p>
<p class="writer">{{displayUrl[index].writer}}</p>
          </v-card>
        </v-col>
      </v-row>
    </template>

    <template>
      <v-data-table
        :headers="headers"
        :items="displayUrl"
        :items-per-page=30
        no-data-text="データがありません"
        class="blog-ranking"
      >
      <tr
        v-for="(item, index) in displayUrl"
        :key="index"
      >        
<td>{{item.ranking[index]}}</td>        
<td>{{item.date[index]}}</td>
<td>{{item.title[index]}}</td>
<td>{{item.writer[index]}}</td>
<td>{{item.pv[index]}} pv</td>
      </tr>

      </v-data-table>
    </template>
  </div>
</template>
<script>
import VueMonthlyPicker from 'vue-monthly-picker'
import moment from 'moment'
import { mapActions } from 'vuex'

export default {
  name: 'home',
  components: {
    VueMonthlyPicker
  },
  data () {
    return {
      selectedMonth: '',
      currentMonth: moment().format('YYYY-MM'),
      startCurrentMonth: moment().format('YYYY-MM-01'),
      endCurrentMonth: moment().format('YYYY-MM-DD'),
      startCurrentSecond: moment().format('YYYY-MM-01T00:00:00'),
      endCurrentSecond: moment().format('YYYY-MM-DDTHH:mm:ss'),
      min: moment('2017/12'),
      lastMonth: moment().endOf('month'),
      perPage: 30,
      article: {
        items: [],
        url: []
      },
      display: {
        date: [],
        title: [],
        writer: [],
        pv: [],
        url: []
      },
      displayUrl: [],
      headers: [
        {text: '順位', sortable: false, value: 'ranking'},
        {text: '投稿日', sortable: false, value: 'date'},
        {text: 'タイトル', sortable: false, value: 'title'},
        {text: '投稿者', sortable: false, value: 'writer'},
        {text: 'PV', sortable: true, value: 'pv'},
      ],
      bgColor: '#1d4c65'
    }
  },
  async created () {
    this.selectedMonth = moment()
    await this.getBlogDetail()
    await this.getData()
    await this.arrayToObject()
  },
  watch: {
    selectedMonth: async function(newDate, oldDate) {
      if (!oldDate) return
      this.crearDate()
      if (newDate.format('YYYY-MM') == this.lastMonth.format('YYYY-MM')) {// 選択が今月だったら
        this.startCurrentMonth = this.selectedMonth.startOf('month').format('YYYY-MM-DD')
        this.endCurrentMonth = moment().format('YYYY-MM-DD')
        this.startCurrentSecond = this.selectedMonth.startOf('month').format('YYYY-MM-DDT00:00:00')
        this.endCurrentSecond = moment().format('YYYY-MM-DDTHH:mm:ss')
      } else {// 選択が今月以外だったら
        this.startCurrentMonth = this.selectedMonth.startOf('month').format('YYYY-MM-DD')
        this.endCurrentMonth = this.selectedMonth.endOf('month').format('YYYY-MM-DD')
        this.startCurrentSecond = this.selectedMonth.startOf('month').format('YYYY-MM-DDT00:00:00')
        this.endCurrentSecond = this.selectedMonth.endOf('month').format('YYYY-MM-DDT23:59:59')
      }
      await this.getBlogDetail()
      await this.getData()
      await this.arrayToObject()
    }
  },
  methods: {
    ...mapActions({
      getBlog: 'blog/getBlog',
      getGAnalytics: 'gAnalytics/getGAnalytics'
    }),
    crearDate () {//初期化
      this.currentMonth = '',
      this.startCurrentMonth = '',
      this.endCurrentMonth = '',
      this.startCurrentSecond = '',
      this.endCurrentSecond = '',
      this.article.items = [],
      this.article.url = [],
      this.display.date = [],
      this.display.title = [],
      this.display.writer = [],
      this.display.pv = [],
      this.display.url = [],
      this.displayUrl = []
    },
    async getBlogDetail () {//wpから情報取得
      const res = await this.getBlog({
        params: {
          after: this.startCurrentSecond,
          before: this.endCurrentSecond,
          perPage: this.perPage
        }
      })
      const data = res.data
      if (data) {
      this.article.items.push(data)
      } else {
        alert('WordPressからの情報取得に失敗しました。')
      }
    },
    async getData () {//GA Reporting APIから情報取得
      const res = await this.getGAnalytics({
        params: {
          start: this.startCurrentMonth,
          end: this.endCurrentMonth,
          selectedMonth: this.selectedMonth.format('YYYYMM'),
          conditions: this.selectedMonth.format('YYYYMM')
        },
        gapi: this.$gapi
      })
      const data = res.data
      if (data) {
        for (let gaCount = 0; gaCount < data.length; gaCount++) {
          const gaUrl = data[gaCount].dimensions[1] //GAから取得したurl情報を順番に格納
          const gaPv = data[gaCount].metrics[0].values[0] //GAから取得したpv情報を順番に格納
         
          for (let wpCount = 0; wpCount < this.article.items[0].length; wpCount++) {//事前に取得したwpからの情報をfor文で回して順番に格納
            const wp = this.article.items[0]//wpから取得した情報を一旦ここにまとめた
            const wpUrl = wp[wpCount].link.replace('https://swallow-incubate.com', '')//ドメインの文字列を削除
            const wpDate = wp[wpCount].date.slice(0, -9)//投稿日(お尻の時間を削除)
            const wpTitle = wp[wpCount].title.rendered//ブログタイトル
            const wpWriter = wp[wpCount].blog_tag[0]//投稿者

            if (gaUrl == wpUrl) {//GAのURLとwpのURLが同じだったら

              if(this.display.url.some(checkUrl => checkUrl == wpUrl)) {//一度格納したURLと同じものがまた回ってきたら
                for (let diff = 0; diff < this.display.url.length; diff++) {
                  if(wpUrl == this.display.url[diff]) {
                    const total = parseInt(this.display.pv[diff]) + parseInt(gaPv)//文字列を整数に変換
                    this.display.pv[diff] = total//元のPV数に後から回ってきたPV数を追加する
                  }
                }
                break
              } else {//一度も格納したことのないURLならこっち
                this.display.date.push(wpDate)//投稿日を格納
                this.display.title.push(wpTitle)//投稿者を格納
                this.display.url.push(wpUrl)//URLを格納
                this.display.pv.push(gaPv)//PV数を格納

                let member = ''
                switch (wpWriter) {
                  case ●●:
                    member = 'メンバー1';
                    this.display.writer.push(member)
                    break
                  case ■■:
                    member = 'メンバー2';
                    this.display.writer.push(member)
                    break
                  default:
                    member = '不明'
                    this.display.writer.push(member)
                    break
                }
              }
            }
          }
        }
      }
      else {
        alert('GAからのデータ取得に失敗しました。')
      }
    },
   
    async arrayToObject () {//PVでソートし直し
      for (let i = 0; i < this.display.url.length; i++) {
        this.displayUrl.push({
          "url": this.display.url[i],
          "ranking": i+1,
          "date": this.display.date[i],
          "title": this.display.title[i],
          "writer": this.display.writer[i],
          "pv": parseInt(this.display.pv[i])
        })
      }
      this.displayUrl.sort((a, b) => {
        if (a.pv > b.pv) {
          return -1
        } else {
          return 1
        }
      })
      for (let i = 0; i < this.display.url.length; i++) {//ランキングの数字を再計算
        this.displayUrl[i].ranking = i + 1
      }
    }
  },
  computed: {
    limitCount() {//TOP3のみを表示
      return this.displayUrl.slice(0, 3)
    }
  }
}
</script>

 

src/store/index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'home',
    component: () => import('../views/Home.vue')
  },
  {
    path: '/three-months',
    name: 'threeMonths',
    component: () => import('../views/ThreeMonths.vue')
  }
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router

 

src/store/modules/blog.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import axios from 'axios'

export const blog = {
  namespaced: true,
  state: {
    url: 'https://swallow-incubate.com/wp-json/wp/v2/blog?'
  },
  actions: {
    async getBlog (state, obj) {
      const ApiURL = state.state.url + 'after=' + obj.params.after + '&before=' + obj.params.before + '&per_page=' + obj.params.perPage
      const result = await axios.get(ApiURL)
      .then(res => {
        if (res.status === 200) {
          return {
            result: true,
            data: res.data
          }
        } else {
          return {
            result: false,
            code: res.code,
            data: []
          }
        }
       
      })
      .catch(error => {
        if(error.message) {
          if (Array.isArray(error.message)) {
            let message = []
            for (let err of error.message) {
              message.push(err.msg)
            }
            return {
              result: false,
              data: message.join(',')
            }
          } else {
            return {
              result: false,
              data: error.message
            }
          }
        } else {
          return {
            result: false,
            data: error
          }
        }
      })
      return result
    }
  }
}

 

src/store/modules/gAnalytics.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
export const gAnalytics = {
  namespaced: true,
  state: {
    url:'https://analyticsreporting.googleapis.com/v4/reports:batchGet',
    viewId: '[viewId]'
  },
  actions: {
    async getGAnalytics ({state}, obj) {
      const requestParams = {
        reportRequests: [
          {
            viewId: state.viewId,
            dateRanges: [
              {
                startDate: obj.params.start,
                endDate: obj.params.end,
              }
            ],
            metrics: [
              {
                expression: 'ga:pageviews'
              }
            ],
            dimensions: [
              {
                name: 'ga:pageTitle'
              },
              {
                name: 'ga:pagePath'
              }
            ],
            dimensionFilterClauses: [{
              filters: [{
                dimensionName: 'ga:pagePath',
                expressions: [
                  obj.params.selectedMonth
                ]
              },
              {
                dimensionName: 'ga:pagePath',
                expressions: [
                  obj.params.conditions
                ]
              }
            ]
            }],
            orderBys: [{
              fieldName: "ga:pageviews",
              sortOrder: "DESCENDING"
            }]
          }
        ]
      }
      const result = await obj.gapi.request({
        path: state.url,
        method: 'POST',
        body: requestParams,
        headers: {
          'content-Type': 'application/json'
        }
      })
      .then(res => {
        if (res.status === 200) {
          return {
            result: true,
            data: res.result.reports[0].data.rows
          }
        } else {
          return {
            result: false,
            code: res.code,
            data: []
          }
        }
         
      })
      .catch(err => {
        console.log('gAnalytics', err)
      })
      return result
    }
  }
}

 

完成イメージ

cssもちゃんと設定してあげて、こんな感じになりました。

 

スワブロランキング

 

これは、2月1日〜2月29日までに公開されたブログで、かつ2月1日〜2月29日までのPV数をカウントした1ヶ月のランキング画面になっております!
1ヶ月単位で見ると、そんな大した数字ではないのですが…3ヶ月ごとになると、トップ5くらいが爆発的な数字になってるんですよね。

 

1位は大体あの方がさらっと取っていくのですが、2&3位争いはいつも熾烈を極めているスワブロです。

コードの説明

さてさて、垂れ流しで紹介したコードですが…ざっくり説明しますね!

 

src/main.js

インストールしたvue google apiをimportして、作成したGoogle APIの情報を入れます。
clientId = OAuth2.0クライアントIDから作成したクライアントID
apiKey = APIキーから作成したキー

 

 

src/App.vue

外枠を作ってあげてます。
コンポーネンツにBaseLine.vueを作っているので、そちらの読み込みをしています。

 

 

src/components/BaseLine.vue

vuetifyのナビゲーションドロワーを使っています。
ここでは、1ヶ月と3ヶ月のランキングへのメニューを作っていますが、今回は1ヶ月ランキングのみ紹介します。

 

 

src/views/Home.vue

html部分ではtop3をvuetifyのcardでレイアウトしています。
テーブルはvuetifyのData tableを使用しています(手動ソートにも対応しているため、超便利!)

 

script部分は細かいものはコメントで説明しましたが、ざっくり説明するとこんな感じ。

  1. セレクトボックスに今月を代入
  2. WPからデータを取得
  3. GA Reporting APIからデータを取得
  4. 上記で集計して、ソートがおかしければ再集計

 

ちなみに、セレクトボックスは年月のみの選択となっていますが、script内ではこんな感じになっています。

〜今月(今日が2020年4月03日11時00分00秒の場合)〜
集計開始日:2020-04-01
集計終了日:2020-04-03
集計開始日(秒まで):2020-04-01T00:00:00
集計終了日(秒まで):2020-04-03T11:00:00

 

〜今月以外(2月を選択した場合)〜
集計開始日:2020-02-01
集計終了日:2020-02-29
集計開始日(秒まで):2020-02-01T00:00:00
集計終了日(秒まで):2020-02-29T23:59:59

 

今月以外だったら1ヶ月分をごっそり集計しちゃえばいいのですが、今月の場合は今日のなうタイムまでのデータしか作成されていないので…今月以外と同じ処理でデータをgetすると「んなデータねぇーよ!この野郎!」と怒られますww
そのためにwatchのif部分は細かく設定してあげてます。

 

あと268行でPVでソートし直しとありますが…
ここは、恐らくやらなくても大丈夫なんです。

 

ただ、弊社の場合ちょっと前にサーバー移管とかなんやらやって、数ページだけGAで取得している情報が同じURLなのに別れてる…という珍事象がありまして(原因がこれかは分かりませんが…
GA上では合体しているんですが、APIから取得してくると別れてるんです。

 

archives/blog/xxxxxxxx/:500pv
archives/blog/xxxxxxxx/:2pv

 

みたいな?
中村さんから月間発表されて「たくやが1位になったのに、こっちのアプリではたくや3位なんですけどwwwあれ?分裂してるwww」っていうね。

 

 

 

src/store/index.js

コードがゴチャゴチャしてくるため、modules/blog.js, modules/gAnalytics.jsというモジュールを作って管理しています。

 

 

src/store/modules/blog.js

Home.vueでまとめたparams(after, before, perPage)を受け取り、それをWP Rest APIに投げて、statusが200だったらdataに格納して、Home.vueに値をぶん投げてます。

 

参照:WP REST API

 

 

src/store/modules/gAnalytics.js

Home.vueでまとめたparams(start, end, selectedMonth, conditions)を受け取り、reportRequestsに条件を当てはめていきGA Reporting APIに投げて、statusが200だったらdataに格納して、Home.vueに値をぶん投げてます。

 

参照:リファレンスガイドQuery Explorer

 

まとめ

いかがでしたでしょうか?
超ローングな内容だったので、大分はしょっちゃいました😋
一応私のローカルでは動いてるんですが…だ、大丈夫かな(ひやひや

 

 

次の問題は、社内サーバーにあげようとしたらGoogle APIが「IPアドレスじゃ受け付けませんぜ!」と弾くんで、そこで頭を抱えています。
中村さんに使ってもらえなかったら、作った意味がーーー😭

 

ちなみに、このアプリはGAで見る権限がないと見れないのも注意!
(多分誰でも見られる方法もある気はするが…とりあえず、社内で見られればでこんな感じにしています)

 

 

無事、スワローメンバーに見てもらえる日が来ることを祈って…このブログを締めたいと思います!

 

 

 

ではっ!

 

 


Top