Techioz Blog

サービス アカウントを使用して GA4 API への Ruby REST リクエストを承認するにはどうすればよいですか?

概要

GA4 API ライブラリから特定のページ パスのビュー数を取得しようとしています。 Ruby GA4 API クライアント gem google-analytics-data を使用してこれを行うことができましたが、GA4 Query Explorer と Ruby API コードの間では結果が大きく異なるため、基本的な REST リクエストを使用して結果を比較したいと考えています。一部のパスでは同じカウントが生成されますが、ほとんどのパスでは同じカウントが生成されません。

エラーが発生し続けます

/var/lib/gems/2.7.0/gems/googleauth-1.11.0/lib/googleauth/service_account.rb:87:in `unescape': undefined method `gsub' for nil:NilClass (NoMethodError)

このエラーは次の行によって生成されます。

credentials = Google::Auth::ServiceAccountCredentials.make_creds(
     scope: claims[:scope],
     json_key: private_key
  )

gsub を削除してもエラーが生成されるため、コード内の gsub 行は関係ありません。

これが私の完全なコードです。

#!/usr/bin/ruby

require 'googleauth'  
require 'net/http'
require 'json'
require 'time'
require './environment' 
error_message = nil

module GoogleAnalytics

    def self.make_ga4_rest_request(body)
      # Define GA4 Reporting API endpoint URL
      
      endpoint = "https://analyticsreporting.googleapis.com/v4/reports:batchGet"

      key_data = JSON.parse(File.read(SERVICE_ACCOUNT_KEY_FILE))
      
      private_key = key_data['private_key'].gsub("\n", "")

      puts private_key.inspect
   
      claims = {
         iss: SERVICE_ACCOUNT_EMAIL,
         scope: AUDIENCE,
         aud: AUDIENCE,
         exp: (Time.now + 60 * 60).to_i  # JWT expires in 1 hour
         }
        
      credentials = Google::Auth::ServiceAccountCredentials.make_creds(
         scope: claims[:scope],
         json_key: private_key
      )
        
      jwt = credentials.authorization.id_token
        
      headers = {
        "Content-Type": "application/json",
        "Authorization": "Bearer #{jwt}"
      }
             
      # Prepare the Net::HTTP request object
      uri = URI(endpoint)
      https = Net::HTTP.new(uri.host, uri.port)
      https.use_ssl = true
      request = Net::HTTP::Post.new(uri)

      # request.set_header!(*headers) newer ruby versions
      headers.each do |key, value|
        request.add_field(key, value)
      end

      request.body = body.to_json

            # Send the request and handle response
      response = https.request(request)
      if response.is_a?(Net::HTTPSuccess)
        JSON.parse(response.body)
      else
        error_message = "Error making GA4 request: #{response.code} - #{response.message}"  
        puts "Error message: #{error_message}"
        puts "Response object: #{response.body}"  # Print thend
      end  
    end
end

完全を期すために含めたクエリの本文は次のとおりです

 body = {
                      "reportRequests": [
                        {
                        "property": "properties/#{PROPERTY_ID}", 
                        "dateRanges": [{"startDate": report_start_date, "endDate": report_end_date}],
                        "metrics": [{"expression": "ga:screenPageViews"}],
                        "dimensions": [{"name": "ga:pagePath"}],
                        "filters": [{"field": "ga:pagePath", "operator": "REGEXP_CONTAINS", "value": page}], 
                        }
                      ]
                    }

解決策

require 'googleauth'
require 'net/http'
require 'json'
require 'time'
require './environment'  # Make sure you've defined SERVICE_ACCOUNT_KEY_FILE, SERVICE_ACCOUNT_EMAIL, AUDIENCE, PROPERTY_ID, etc.

module GoogleAnalytics
  def self.make_ga4_rest_request(body)
    # Define GA4 Reporting API endpoint URL
    endpoint = "https://analyticsreporting.googleapis.com/v4/reports:batchGet"

    key_data = JSON.parse(File.read(SERVICE_ACCOUNT_KEY_FILE))
    private_key = key_data['private_key'].gsub("\n", '')

    claims = {
      iss: SERVICE_ACCOUNT_EMAIL,
      scope: AUDIENCE,
      aud: AUDIENCE,
      exp: (Time.now + 60 * 60).to_i  # JWT expires in 1 hour
    }

    credentials = Google::Auth::ServiceAccountCredentials.make_creds(
      scope: claims[:scope],
      json_key: private_key
    )

    jwt = credentials.authorization.id_token

    headers = {
      'Content-Type': 'application/json',
      'Authorization': "Bearer #{jwt}"
    }

    # Prepare the Net::HTTP request object
    uri = URI(endpoint)
    https = Net::HTTP.new(uri.host, uri.port)
    https.use_ssl = true
    request = Net::HTTP::Post.new(uri)

    headers.each do |key, value|
      request.add_field(key, value)
    end

    request.body = body.to_json

    # Send the request and handle response
    response = https.request(request)
    if response.is_a?(Net::HTTPSuccess)
      JSON.parse(response.body)
    else
      error_message = "Error making GA4 request: #{response.code} - #{response.message}"
      puts "Error message: #{error_message}"
      puts "Response object: #{response.body}"
    end
  end
end

# Example usage:
body = {
  "reportRequests": [
    {
      "property": "properties/#{PROPERTY_ID}",
      "dateRanges": [{"startDate": report_start_date, "endDate": report_end_date}],
      "metrics": [{"expression": "ga:screenPageViews"}],
      "dimensions": [{"name": "ga:pagePath"}],
      "filters": [{"field": "ga:pagePath", "operator": "REGEXP_CONTAINS", "value": page}]
    }
  ]
}

result = GoogleAnalytics.make_ga4_rest_request(body)
puts result

プレースホルダー (SERVICE_ACCOUNT_KEY_FILE、SERVICE_ACCOUNT_EMAIL、AUDIENCE、PROPERTY_ID など) を実際の値に置き換えてください。この変更されたコードは、サービス アカウントの資格情報を使用して GA4 API への REST リクエストを正しく承認する必要があります。