2019年11月6日水曜日

google-api-javascript-client を使ってみた

概要

google-api-javascript-client を使ってみました
OAuth の実行方法と認証後にセッショントークンを使って Compute の API をコールするところまで試してみました

環境

  • macOS 10.15
  • google-api-javascript-client (2019/11/05 時点)

アプリ雛形作成

  • bundle init
  • vim Gemfile
gem "sinatra"
  • bundle install --path vendor
  • vim config.ru
require './app'
run TestWebApp
  • vim app.rb
require 'sinatra/base'

class TestWebApp < Sinatra::Base
  get '/' do
    erb :index
  end
end
  • mkdir views
  • touch views/index.erb

OAuth クライアントの作成

まずはおなじみに OAuth クライアントの作成から行います
作成したらクライアントID とクライアントシークレットをメモしましょう

JavaScript の SDK の場合クレデンシャルファイルを使った認証はできないので文字列の ID とシークレットを使います

OAuth だけ実装してみる

では先に OAuth だけ実装してみましょう
作成した erb ファイルに実装していきます

  • vim views/index.erb
<html>
  <head>
    <title></title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
    <script src="https://apis.google.com/js/client.js"></script>
    <script type="text/javascript">
      var PROJECT_ID = 'pjct-1234';
      var CLIENT_ID = '123456789012-asdfghjklqwertyuiopzxcvbnm.apps.googleusercontent.com';
      var API_KEY = 'api-key';
      var SCOPES = 'https://www.googleapis.com/auth/compute';
      function authorization() {
        gapi.client.setApiKey(API_KEY);
        gapi.auth.authorize({
          client_id: CLIENT_ID,
          scope: SCOPES,
          immediate: false
        }, function(authResult) {
      console.log(authResult.access_token);
          if (authResult && !authResult.error) {
            $('#ret').text('success');
          } else {
            $('#ret').text('error');
          }
        });
      }
      $(window).load(authorization);
    </script>
  </head>
  <body>
    <p id="ret"></p>
  </body>
</html>

PROJECT_ID は自身の使っているプロジェクトの ID を設定してください
CLIENT_ID, API_KEY は先程メモしておいたものを使ってください

解説

まず SDK を読み込みます

  • <script src="https://apis.google.com/js/client.js"></script>

今回は JQuery も使っています
次に OAuth の処理を実装します
gapi.client.setApiKey で API_KEY をセットします
そして gapi.auth.authorize を使って認証します
今回はスコープに compute の API をコールするためのスコープを追加しています
immediate パラメータは true にすると動作しなかったのでとりあえず false にしています
true にすると認証時にポップアップが表示されないようなのですが動作しなかったので false にしています

あとは認証後のコールバックの関数部分を実装しています
今回は認証の結果だけを表示しています
authResult オブジェクトにセッショントークンの情報が入っています
実際に compute の API をコールするときはこの authResult オブジェクトから勝手に access_token を取得してコールしてくれるので意図的に参照するケースはないかなと思います

動作確認

  • bundle exec rackup config.ru

http://localhost:9292 にアクセスすると認証用のポップアップが表示されます
おそらくポップアップがブロックされるので許可して動作確認しましょう

アカウントを選択します

localhost からのアクセスなので警告がでますがテストなので無視します

compute への権限を許可します

権限を確認して許可しましょう

あとは「success」と表示されれば認証完了です
コンソールにも authResult の情報が表示されているのが確認できると思います

Compute の API をコールする処理を追加

セッショントークンが取得できたら Compute の API をコールしてみましょう

  • vim views/index.erb
<html>
  <head>
    <title></title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
    <script src="https://apis.google.com/js/client.js"></script>
    <script type="text/javascript">
      var PROJECT_ID = 'pjct-1234';
      var CLIENT_ID = '123456789012-asdfghjklqwertyuiopzxcvbnm.apps.googleusercontent.com';
      var API_KEY = 'api-key';
      var SCOPES = 'https://www.googleapis.com/auth/compute';
      var API_VERSION = 'v1';
      var DEFAULT_PROJECT = PROJECT_ID;
      var DEFAULT_ZONE = 'us-central1-c';
      var DISCOVERY_DOCS = ['https://www.googleapis.com/discovery/v1/apis/compute/v1/rest'];
      function authorization() {
        gapi.client.setApiKey(API_KEY);
        gapi.auth.authorize({
          client_id: CLIENT_ID,
          scope: SCOPES,
          immediate: true
        }, function(authResult) {
          if (authResult && !authResult.error) {
            $('#auth_ret').text('success');
            gapi.client.init({
              discoveryDocs: DISCOVERY_DOCS,
              client_id: CLIENT_ID,
              scope: SCOPES
            }).then(function() {
              var request = gapi.client.compute.instances.list({
                'project': DEFAULT_PROJECT,
                'zone': DEFAULT_ZONE
              });
              request.execute(function(resp) {
                $('#ret').text('success');
                resp.items.forEach(function(i) {
                  $('#instances').append("<li>" + i.name + "</li>");
                });
              });
            })
            .catch(function() {
              $('#ret').text('error');
            });
           } else {
            $('#auth_ret').text('error');
          }
        });
      }
      $(window).load(authorization);
    </script>
  </head>
  <body>
    <h1>Auth</h1>
    <p id="auth_ret"></p>
    <h1>Compute API</h1>
    <p id="ret"></p>
    <ul id="instances"></ul>
  </body>
</html>

デフォルトのゾーンを調べる方法は以下のコマンドを実行しましょう

  • gcloud compute project-info describe --project pjct-1234

デフォルトゾーンが設定されていない場合は自分のインスタンスが存在しているゾーンを設定しましょう

解説

認証後のコールバックメソッドに compute の API をコールする処理を追加しています
今回はすべて同じメソッド内で実装していますが分けても問題ないです

まず gapi.client.init で Compute の API をコールするためのクライアントを初期化します
初期化する際には discoveryDocs という API の定義が配布されている URL があるのでこれを指定します
Compute API の場合は https://www.googleapis.com/discovery/v1/apis/compute/v1/rest になります

次にクライアントの初期化が完了したら API をコールします
gapi.client.compute.instances.list というメソッドを使います
client のあとに「API 名」「リソース名」「操作名」という規則でコールすることができます
引数などは操作名ごとにことなるのでリファレンスを確認してください

最後に結果を受け取ってそれを HTML に表示して終了です
レスポンスの形式は一度 cosole.log などで覗いてみると扱いやすいと思います

ハマリポイント

gapi.client.load は Deprecated になっておりクライアントを初期化する場合は gapi.client.init + discoveryDocs を使いましょう
自分はこの方法にたどり着くまでに「gapi.client.compute is undefined」というエラーにずっと悩まされました
実は gapi.client.load が正常に行われていないために gapi.client.compute が生成されていないのが原因でした

動作確認

  • bundle exec rackup config.ru

http://localhost:9292 にアクセスすると認証用のポップアップが表示されます
すでに認証済みの場合はすぐにポップアップが閉じると思います

しばらくすると以下のようにインスタンスの情報が表示されると思います

最後に

google-api-javascript-client を使って OAuth 処理の実装と Compute API のコールをしてみました
情報があまりなく Compute API をコールするときに少しハマりました

HTML と JavaScript だけで完結するのでサーバが不要な場合に使える方法かなと思います

参考サイト

0 件のコメント:

コメントを投稿