LoginSignup
30
16

LaravelでGoogleSheetAPIを叩き、本番環境で詰みまくった件

Last updated at Posted at 2023-06-05

やりたいこと

Google Sheet APIを通して、Laravelからスプレットシートの情報を取得し、表示させる!!

なぜやりたいか?

今回は100以上の項目のある測定テストを作成して、回答者が自分が回答した問題をRadar Chartで見せたい。ユーザー側は自分の情報をいつでも見れるように、Laravel Breezeを使って、ログインし、自分が回答した結果を見れる仕組みにしたい。

作りたい仕組みはこちら:

スクリーンショット 2023-06-05 23.56.03.png

つまり、LaravelでAPIを扱うことに

LaravelのView画面からJavaScriptでAPIを叩いたことありますが、今回はコントローラからAPI情報を入れてみました。

理由はGoogleスプレットシートの共有部分に、共有するメールアドレスが必要(後ほど説明!)のと、JavaScript以外のやり方にチャレンジしたかったです。

やってみたこと:

① Google Cloud PlatformでSheetAPIを有効にし、サービスキーを作成する
② Laravelのコントローラから認証情報を取得
③ Chart.jsでデータを処理して反映する

③はChart.jsを調べればすぐできますので、今回は認証情報とLaravelで苦戦したところを共有します。

今回使ったChart.jsのサンプルコードはこちら

苦戦した部分

苦戦の連続でした。主に情報取得と引き渡し、そして本番環境でめちゃくちゃ詰んだ。

苦戦①:どのキーを使えば情報を取得できるの?

SheetAPIを動かしたいので、どんな認証方法がいいの?APIキーでもいいの?
正直、イマイチ理解してなかった。GCPを開いたら、3つもある!!

スクリーンショット 2023-06-06 0.29.33.png

  1. API キー
  2. OAuth 2.0 クライアント ID
  3. サービス アカウント

公式から、細かく説明があります。

ざっくりと言いますと、今回はスプレットシートの情報を取得したいので、スプレットシートの権限をもらう必要があります。だから、スプレットシートから共有が必要ですので、サービスアカウントキーが最も簡単で便利です。(セキュリティも悪くないようです。)

補足: なぜAPIキーはダメでしたか?
公式ドキュメンテーションによると、多くのAPIがAPIキーに対応しないそうです。つまり、コードを書けたら、OAuthがいい、スプレットシートくらいなら、サービスアカウントだったら手っ取り早い!!

手順:

① もらったサービスアカウントの情報を入力
スクリーンショット 2023-06-06 0.40.47.png

② サービスキーのJSONファイルをダウンロード
詳しい設定はこちらの記事を参考しました。設定時ダウンロードしないと、2度と取得できないようです。

③ サービスキーファイルをStorageに保存

※ここは結構大事です!! めちゃくちゃ詰んだ部分です。

いろいろ試したあと、Storage/App/private/の下で配置するようにしました。理由はセキュリティ上、アクセスしにくい場所がいい。そして、.envファイルのように、本番環境で多量の手打ちすることもない。

苦戦②:情報をどう取得すればいいの?

認証取得だけで、二日ほど苦戦しました。見飽きたエラーはこちらです。

データの取得に失敗しました SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON

データ取得できない時によく出るSyntaxエラーらしい。このエラーが登場する時、考えられる可能性は、

  1. 認証情報が間違ってる。
  2. 設定ミス
  3. サービスキーのファイルはあっていますが、パスが通ってない。

実際コントローラで書いたコードはこんな感じです。

$client = new Google_Client();
        $key_file = storage_path('app/private/credential.json'); 
        $client->setAuthConfig($key_file);
        $client->setScopes([
            'https://www.googleapis.com/auth/spreadsheets'
        ]);

先ほど話したサービスキーファイルを storage/app/private/credential.json
で保存します。パスの通し方はこんな感じ:storage_path('app/private/credential.json');

あとはわりとシンプルです。スプレットシートの情報を取得し、response経由でviewの方に引き渡すだけです。

        $sheetId = '1ml44HFe1tGhl7_eJgIbB4EQjDusAami3gRUTA64zdps';
        
        $sheetService = new Google_Service_Sheets($client);
        $range = 'Sheet1'; // Sheet1の内容全てを取得
   
        
        $response = $sheetService->spreadsheets_values->get($sheetId, $range);
        $values = $response->getValues();//データを配列で取得
    

        // return response()->json($values);// 取得したデータをチェックするときはこちらを
        return response()->view('googleSheet',compact('values'));//viewの方に取得したデータを引き渡し

苦戦③:本番環境で詰んだ

今回はさくらサーバーでデプロイしました。デプロイした瞬間、動いてたChart.jsが動かなくなりました。なぜだ!!!!!

可能性をいろいろ模索しました。やってみてもうまくいかなかったこと:

・.envファイルでのphpMyAdmin設定
・google clould jsonキーは本番環境に入れる

そして、同期からもらったアドバイス:

・セキュリティー関連のパーミッション問題
・ローカルと本番のギャップによるマシン問題
・そもそも認証が間違ってる
などなど

ほぼ総当てして、最終的に動かせた。
正直どれか正解なのかわかりませんが、最後に試したことはこれです。

fetch("{{ route('sheet') }}?email=" + email,{
            //本番環境入ってから追加項目
            headers : { 
            'Content-Type': 'application/json',
            'Accept': 'application/json'
            }
           })

'Content-Type': 'application/json'を明記することによって、引き渡されたファイルはちゃんとJSONファイルですよ〜ということらしいです。

本番環境はローカル環境より厳格ということかな?
viewのコードはこちら:

<body>
//認証機能
    @auth
    <div class="flex justify-center">
    <input type="hidden" id="email" name="email" value="{{ auth()->user()->email }}">
   <x-primary-button id="fetchData" class="mt-4 mb-4 py-2 px-4 bg-blue-500 text-black rounded-lg">結果表示</x-primary-button>

    </div>
     @endauth
       
//canvasを使ってChart.jsを表示・描画
    <canvas id="radarChart"></canvas>

    <script>
        // データ取得用のAjaxリクエストを送信する関数
        function fetchData() {
            const email = document.getElementById('email').value;
            // Ajaxリクエストを送信
            fetch("{{ route('sheet') }}?email=" + email,{
            
            headers : { 
            'Content-Type': 'application/json',
            'Accept': 'application/json'
            }
           })
           .then(response => response.json())
                
                .then(data => {
                    // データを取得してレーダーチャートを描画する関数を呼び出す
                    drawRadarChart(data);
                })
                  .catch(error => {
                     console.error("データの取得に失敗しました", error);
                 });
              
        }
       
        // レーダーチャートを描画する関数
        function drawRadarChart(data) {
            
         //引き渡されたデータの処理は割愛。こっからはChart.jsのサンプルコードを参照

            const canvas = document.getElementById('radarChart');

            new Chart
            (canvas, {
                type: 'radar',
                data: {
                    labels: [
                    'label1', 
                    'label2', 
                    'label3',  
                    'label4',  
                    'label5',  
                    'label6',  
                    'label7', 
                    ],
                    datasets: [{
                        label: `${timestamp}`,
                        data: [Q1result,Q2result,Q3result,Q4result,Q5result,Q6result,Q7result],
                        fill: true,
                        backgroundColor: 'rgba(75, 192, 192, 0.2)',
                        borderColor: 'rgba(75, 192, 192, 1)',
                        borderWidth: 1
                    }]
                },
                options: {
                    scale: {
                        ticks: {
                            beginAtZero: true,
                            max: 100
                        }
                    }
                }
            });
        }
        

        // データ取得ボタンのクリックイベントを設定
        document.getElementById('fetchData').addEventListener('click', fetchData);
    </script>
</body>

引き渡されたデータをJavaScriptで処理して、完成!!

感想

本番環境でもチャートが表示されました!!! 歓喜!!!!!

スクリーンショット 2023-06-06 1.36.35.png

いろんな人の協力を得て、なんとかできました。これからは複数のデータを重ねていく仕組みを考えます。
引き続き、GoogleAPIサービスを使っていきたいと思います^^

最後に、、、最近の私。

携わっているByNameがリリースして、私のプロフィールもぜひみてもらいたいと思ってます!!

30
16
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
30
16