1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Google Business Profileのレビュー投稿を検知する機能作成

Posted at

Google Business Profile APIs 通知(URL)

主にGoogle Business Profile APIsの通知設定について記述してます。
GBP公式ドキュメントを参照していましたが、設定方法がわかりにくかったので記事にしました。

APIでの通知設定を記載します。

使うもの

  • TypeScript
  • node
  • Google Cloud Platform
    • IAM
    • Pub/Sub (Google Cloud Platform)
  • Google Business Profile APIs
    • 下記に記載してます
  • AWS (省略します)
    • API Gateway
      • Lambda
        • 認証
        • 受け取った際の処理

各種設定

  1. Google Cloud Platform
    1. IAM
      1. PubSub用のサービスアカウントを作る
    2. Pub/Sub
      1. トピックを作る
        1. 権限ロール・プリンシバルを追加
          1. Pub/Sub パブリッシャー権限以上のものを付与
        2. トピックの名前をコピーしておく
      2. サブスクリプションを作る/編集する
        1. 配信タイプ
          1. Push
        2. エンドポイント
          1. 任意のサーバー
        3. 認証
          1. 有効
          2. サービスアカウントIAMで作ったもの
        4. その他はデフォルト設定
  2. Google Business Profile APIs通知設定
    1. 公式ドキュメント参照

APIリクエスト用のアクセストークン取得

/lib/google.ts
import { OAuth2Client } from "google-auth-library";

/**Googleアクセストークン取得 */
export const getGoogleAccessToken = async () => {
  try {
    const oauth2Client = new OAuth2Client(
      process.env.GOOGLE_CLIENT_ID,
      process.env.GOOGLE_CLIENT_SECRET
    )
    oauth2Client.setCredentials({
      refresh_token: process.env.GOOGLE_REFRESH_TOKEN
    })
    const response = await oauth2Client.getAccessToken()
    return response.token
  } catch (error) {
    return null
  }
}

簡易型宣言ファイル

/types/google.d.ts
/** 
 * Google My Business Notification Setting Data
 * @property {string} [name] 通知名 (任意)
 * @property {string} pubsubTopic 通知を送信する Pub/Sub トピック
 * @property {(
* * "NEW_REVIEW" //新規レビュー
* * | "UPDATED_REVIEW" //レビュー更新
* * | "NEW_CUSTOMER_MEDIA" //Googleマップのユーザーによって、新しいメディア アイテムがビジネスに追加
* * | "NEW_QUESTION" //新しい質問がビジネスに追加
* * | "UPDATED_QUESTION" //ビジネスに関する質問が更新
* * | "NEW_ANSWER" //新しい回答がビジネスに追加
* * | "UPDATED_ANSWER" //ビジネスの回答が更新
* * | "GOOGLE_UPDATE" //ビジネス情報に Google による変更
* * | "DUPLICATE_LOCATION" //位置情報メタデータの重複するビジネス情報フィールドに変更
* * | "VOICE_OF_MERCHANT_UPDATED" //ビジネスの Voice of Merchant(VOM)ステータスの更新
* )[]} notificationTypes 通知の種類の配列
*  @example
* ```javascript
* const notificationData: NotificationData = {
*   name: 'accounts/{accountID}/notificationSetting',
*   pubsubTopic: 'projects/my-project/topics/reviews',
*   notificationTypes: ['NEW_REVIEW'],
* };
* ```
* */
interface _BusinessNotificationData {
  name?: string
  pubsubTopic: string
  notificationTypes: (
    | "NEW_REVIEW"
    | "UPDATED_REVIEW"
    | "NEW_CUSTOMER_MEDIA"
    | "NEW_QUESTION"
    | "UPDATED_QUESTION"
    | "NEW_ANSWER"
    | "UPDATED_ANSWER"
    | "GOOGLE_UPDATE"
    | "DUPLICATE_LOCATION"
    | "VOICE_OF_MERCHANT_UPDATED"
  )[]
}

import

/notification/route.ts
import { logger } from "@/lib/aws/amplifyConfig"
import { getGoogleAccessToken } from "@/lib/google"
import { _BusinessNotificationData } from "@/types/google"
import { NextRequest, NextResponse } from "next/server"

通知設定を取得する

/notification/route.ts
export const GET = async (req: NextRequest) => {
  try {
    const googleAccessToken = await getGoogleAccessToken()
    const accountId = process.env.GOOGLE_ACCOUNT_ID
    const url = `https://mybusinessnotifications.googleapis.com/v1/accounts/${accountId}/notificationSetting`

    const response = await fetch(url, {
      method: "GET",
      headers: {
        "Content-Type": "application/json",
        "Authorization": `Bearer ${googleAccessToken}`
      },
    })

    if (!response.ok) {
      logger.warn("[GBP通知][情報取得][失敗]")
      return NextResponse.json({ message: "GoogleMyBusinessから情報取得できませんでした" }, { status: 400 })
    }

    const myBusinessNotifications = await response.json()
    logger.debug("[GBP通知][情報取得][成功]")
    return NextResponse.json(
      { myBusinessNotifications },
      { status: 200 }
    )

  } catch (error) {
    logger.error("[GBP通知][情報取得][エラー]")
    return NextResponse.json(
      { message: "Failed to fetch data", error: error },
      { status: 500 }
    )
  }
}   

通知設定を更新する

/notification/route.ts
/** 値を受け取って更新する仕様にしています*/
export const PATCH = async (req: NextRequest) => {
  try {
    const { notificationTypes }: { notificationTypes: _BusinessNotificationData["notificationTypes"] } = await req.json()
    const googleAccessToken = await getGoogleAccessToken()
    const accountId = process.env.GOOGLE_ACCOUNT_ID
    /** 公式ドキュメントにはpubsubTopicの記載がないが必要*/
    const updateMask = "notificationTypes,pubsubTopic"
    const url = `https://mybusinessnotifications.googleapis.com/v1/accounts/${accountId}/notificationSetting?updateMask=${updateMask}`
    /** 常にレビュー、レビュー更新、GOOGLEによる更新を検知できるように設定しています */
    const data: _BusinessNotificationData = {
      name: `accounts/${accountId}/notificationSetting`,
      pubsubTopic: process.env.PUBSUB_TOPIC_NAME,
      notificationTypes: notificationTypes || [
        'NEW_REVIEW',
        'UPDATED_REVIEW',
        'GOOGLE_UPDATE'
      ],
    }

    const response = await fetch(url, {
      method: "PATCH",
      headers: {
        "Content-Type": "application/json",
        "Authorization": `Bearer ${googleAccessToken}`
      },
      body: JSON.stringify(data)
    })

    if (!response.ok) {
      logger.warn("[GBP通知][情報更新][失敗]")
      return NextResponse.json({ message: "GoogleMyBusinessから情報取得できませんでした" }, { status: 400 })
    }
    const myBusinessNotifications = await response.json()
    logger.debug("[GBP通知][情報更新][成功]")

    return NextResponse.json(
      { myBusinessNotifications },
      { status: 200 }
    )


  } catch (error) {
    logger.warn("[GBP通知][情報更新][エラー]", error)
    return NextResponse.json(
      { message: "Failed to fetch data", error: error },
      { status: 500 }
    )
  }
}

ここで設定したものが検知された際に、PubSubトピックが実行されます。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?